diff options
788 files changed, 36455 insertions, 12126 deletions
diff --git a/Android.bp b/Android.bp index 9426a9c503ed..04b4e6edf2ec 100644 --- a/Android.bp +++ b/Android.bp @@ -205,10 +205,23 @@ filegroup { "wifi/java/**/*.java", "wifi/java/**/*.aidl", ], + exclude_srcs: [ + ":framework-wifi-non-updatable-sources" + ], path: "wifi/java", } filegroup { + name: "framework-wifi-non-updatable-sources", + srcs: [ + // TODO(b/146011398) package android.net.wifi is now split amongst 2 jars: framework.jar and + // framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache + // to a separate package. + "wifi/java/android/net/wifi/WifiNetworkScoreCache.java" + ], +} + +filegroup { name: "framework-non-updatable-sources", srcs: [ // Java/AIDL sources under frameworks/base @@ -233,6 +246,7 @@ filegroup { ":framework-telephony-common-sources", ":framework-telephony-sources", ":framework-wifi-sources", + ":framework-wifi-non-updatable-sources", ":PacProcessor-aidl-sources", ":ProxyHandler-aidl-sources", @@ -253,6 +267,8 @@ filegroup { ":libcamera_client_aidl", ":libcamera_client_framework_aidl", ":libupdate_engine_aidl", + // TODO: this needs to be removed when statsd-framework.jar is separated out + ":statsd_aidl", ":storaged_aidl", ":vold_aidl", @@ -372,12 +388,14 @@ java_defaults { exclude_srcs: [ // See comment on framework-atb-backward-compatibility module below - "core/java/android/content/pm/AndroidTestBaseUpdater.java", + "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java", ], sdk_version: "core_platform", libs: [ + "app-compat-annotations", "ext", + "unsupportedappusage", "updatable_media_stubs", ], @@ -413,18 +431,6 @@ filegroup { } filegroup { - name: "statsd_aidl", - srcs: [ - "core/java/android/os/IPullAtomCallback.aidl", - "core/java/android/os/IPullAtomResultReceiver.aidl", - "core/java/android/os/IStatsCompanionService.aidl", - "core/java/android/os/IStatsManager.aidl", - "core/java/android/os/IStatsPullerCallback.aidl", - ], - path: "core/java", -} - -filegroup { name: "libvibrator_aidl", srcs: [ "core/java/android/os/IExternalVibrationController.aidl", @@ -437,7 +443,6 @@ java_library { name: "framework-minus-apex", defaults: ["framework-defaults"], srcs: [":framework-non-updatable-sources"], - libs: ["app-compat-annotations"], installable: true, javac_shard_size: 150, required: [ @@ -455,6 +460,7 @@ java_library { ], // For backwards compatibility. stem: "framework", + apex_available: ["//apex_available:platform"], } // This "framework" module is NOT installed to the device. It's @@ -475,6 +481,7 @@ java_library { // TODO(jiyong): add stubs for APEXes here ], sdk_version: "core_platform", + apex_available: ["//apex_available:platform"], } java_library { @@ -482,15 +489,18 @@ java_library { defaults: ["framework-defaults"], srcs: [":framework-all-sources"], installable: false, - libs: ["app-compat-annotations"], - static_libs: ["exoplayer2-core"] + static_libs: ["exoplayer2-core"], + apex_available: ["//apex_available:platform"], } java_library { name: "framework-annotation-proc", defaults: ["framework-aidl-export-defaults"], srcs: [":framework-all-sources"], - libs: ["app-compat-annotations"], + libs: [ + "app-compat-annotations", + "unsupportedappusage", + ], installable: false, plugins: [ "unsupportedappusage-annotation-processor", @@ -536,7 +546,7 @@ java_library { installable: true, libs: ["app-compat-annotations"], srcs: [ - "core/java/android/content/pm/AndroidTestBaseUpdater.java", + "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java", ], } @@ -581,6 +591,7 @@ filegroup { "core/java/android/annotation/Nullable.java", "core/java/android/annotation/IntDef.java", "core/java/android/annotation/IntRange.java", + "core/java/android/annotation/SystemApi.java", "core/java/android/annotation/UnsupportedAppUsage.java", "core/java/com/android/internal/annotations/GuardedBy.java", "core/java/com/android/internal/annotations/VisibleForTesting.java", @@ -1690,16 +1701,14 @@ filegroup { } filegroup { - name: "framework-wifistack-shared-srcs", + name: "framework-wifi-service-shared-srcs", srcs: [ ":framework-annotations", - "core/java/android/os/HandlerExecutor.java", + "core/java/android/net/InterfaceConfiguration.java", + "core/java/android/os/HandlerExecutor.java", "core/java/android/util/BackupUtils.java", - "core/java/android/util/KeyValueListParser.java", "core/java/android/util/LocalLog.java", "core/java/android/util/Rational.java", - "core/java/android/util/proto/ProtoStream.java", - "core/java/android/util/proto/ProtoOutputStream.java", "core/java/com/android/internal/util/FastXmlSerializer.java", "core/java/com/android/internal/util/HexDump.java", "core/java/com/android/internal/util/IState.java", diff --git a/TEST_MAPPING b/TEST_MAPPING index 55fa5ed13d79..2b12da291acb 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -7,6 +7,50 @@ "exclude-annotation": "androidx.test.filters.FlakyTest" } ] + }, + { + "name": "ExtServicesUnitTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TestablesTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-annotation": "android.platform.test.annotations.Presubmit" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ] + }, + { + "name": "FrameworksServicesTests", + "options": [ + { + "include-annotation": "android.platform.test.annotations.Presubmit" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ] } ], "postsubmit-managedprofile-stress": [ diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 3204013042c6..1ec96ecc561b 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -2689,7 +2689,7 @@ public class JobSchedulerService extends com.android.server.SystemService } @Override - protected int handleShellCommand(@NonNull ParcelFileDescriptor in, + public int handleShellCommand(@NonNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args) { return (new JobSchedulerShellCommand(JobSchedulerService.this)).exec( diff --git a/apex/sdkext/Android.bp b/apex/sdkext/Android.bp index 40f3c45518bb..aaf25b1d40bb 100644 --- a/apex/sdkext/Android.bp +++ b/apex/sdkext/Android.bp @@ -19,7 +19,6 @@ apex { java_libs: [ "framework-sdkext" ], prebuilts: [ "com.android.sdkext.ldconfig", - "cur_sdkinfo", "derive_sdk.rc", ], key: "com.android.sdkext.key", @@ -43,28 +42,3 @@ prebuilt_etc { filename: "ld.config.txt", installable: false, } - -python_binary_host { - name: "gen_sdkinfo", - srcs: [ - "derive_sdk/sdk.proto", - "gen_sdkinfo.py", - ], - proto: { - canonical_path_from_root: false, - }, -} - -gensrcs { - name: "cur_sdkinfo_src", - srcs: [""], - tools: [ "gen_sdkinfo" ], - cmd: "$(location) -v 0 -o $(out)", -} - -prebuilt_etc { - name: "cur_sdkinfo", - src: ":cur_sdkinfo_src", - filename: "sdkinfo.binarypb", - installable: false, -} diff --git a/apex/sdkext/TEST_MAPPING b/apex/sdkext/TEST_MAPPING new file mode 100644 index 000000000000..91947f39980a --- /dev/null +++ b/apex/sdkext/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "CtsSdkExtTestCases" + } + ] +} diff --git a/apex/sdkext/derive_sdk/derive_sdk.cpp b/apex/sdkext/derive_sdk/derive_sdk.cpp index 0aacebefaaca..7536def60767 100644 --- a/apex/sdkext/derive_sdk/derive_sdk.cpp +++ b/apex/sdkext/derive_sdk/derive_sdk.cpp @@ -68,7 +68,7 @@ int main(int, char**) { auto itr = std::min_element(versions.begin(), versions.end()); std::string prop_value = itr == versions.end() ? "0" : std::to_string(*itr); - if (!android::base::SetProperty("persist.com.android.sdkext.sdk_info", prop_value)) { + if (!android::base::SetProperty("ro.build.version.extensions.r", prop_value)) { LOG(ERROR) << "failed to set sdk_info prop"; return EXIT_FAILURE; } diff --git a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java index c039a820fc04..d3b9397d45f2 100644 --- a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java +++ b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java @@ -17,25 +17,40 @@ package android.os.ext; import android.annotation.IntDef; +import android.annotation.SystemApi; import android.os.Build.VERSION_CODES; import android.os.SystemProperties; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -/** @hide */ +/** + * Methods for interacting with the extension SDK. + * + * This class provides information about the extension SDK version present + * on this device. Use the {@link #getExtensionVersion(int) getExtension} to + * query for the extension version for the given SDK version. + + * @hide + */ +@SystemApi public class SdkExtensions { private static final int R_EXTENSION_INT; static { - R_EXTENSION_INT = SystemProperties.getInt("persist.com.android.sdkext.sdk_info", 0); + R_EXTENSION_INT = SystemProperties.getInt("ro.build.version.extensions.r", 0); } - /** Values suitable as parameters for {@link #getExtensionVersion(int)}. */ + /** + * Values suitable as parameters for {@link #getExtensionVersion(int)}. + * @hide + */ @IntDef(value = { VERSION_CODES.R }) @Retention(RetentionPolicy.SOURCE) public @interface SdkVersion {} + private SdkExtensions() { } + /** * Return the version of the extension to the given SDK. * diff --git a/apex/sdkext/framework/tests/Android.bp b/apex/sdkext/framework/tests/Android.bp deleted file mode 100644 index 3d5dbb3d8a2d..000000000000 --- a/apex/sdkext/framework/tests/Android.bp +++ /dev/null @@ -1,10 +0,0 @@ -android_test { - name: "framework-sdkext-tests", - srcs: ["src/**/*.java"], - libs: [ - "android.test.base", - "android.test.runner", - ], - static_libs: [ "framework-sdkext" ], - platform_apis: true, -} diff --git a/apex/sdkext/framework/tests/AndroidManifest.xml b/apex/sdkext/framework/tests/AndroidManifest.xml deleted file mode 100644 index 831f1328c006..000000000000 --- a/apex/sdkext/framework/tests/AndroidManifest.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2019 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.sdkext.tests"> - - <application> - <uses-library android:name="android.test.runner" /> - </application> - - <instrumentation android:name="android.test.InstrumentationTestRunner" - android:targetPackage="com.android.sdkext.tests" /> - -</manifest> diff --git a/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java b/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java deleted file mode 100644 index 688511096a43..000000000000 --- a/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os.ext; - -import android.os.Build; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.TestCase; - -public class SdkExtensionsTest extends TestCase { - - @SmallTest - public void testBadArgument() throws Exception { - try { - SdkExtensions.getExtensionVersion(Build.VERSION_CODES.Q); - fail("expected IllegalArgumentException"); - } catch (IllegalArgumentException expected) { } - - try { - SdkExtensions.getExtensionVersion(999999); - fail("expected IllegalArgumentException"); - } catch (IllegalArgumentException expected) { } - } - - @SmallTest - public void testDefault() throws Exception { - int r = SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R); - assertTrue(r >= 0); - } - -} diff --git a/apex/sdkext/gen_sdkinfo.py b/apex/sdkext/gen_sdkinfo.py deleted file mode 100644 index 5af478ba7fe6..000000000000 --- a/apex/sdkext/gen_sdkinfo.py +++ /dev/null @@ -1,19 +0,0 @@ -import sdk_pb2 -import sys - -if __name__ == '__main__': - argv = sys.argv[1:] - if not len(argv) == 4 or sorted([argv[0], argv[2]]) != ['-o', '-v']: - print('usage: gen_sdkinfo -v <version> -o <output-file>') - sys.exit(1) - - for i in range(len(argv)): - if sys.argv[i] == '-o': - filename = sys.argv[i+1] - if sys.argv[i] == '-v': - version = int(sys.argv[i+1]) - - proto = sdk_pb2.SdkVersion() - proto.version = version - with open(filename, 'wb') as f: - f.write(proto.SerializeToString()) diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp new file mode 100644 index 000000000000..e6ca544c04be --- /dev/null +++ b/apex/statsd/aidl/Android.bp @@ -0,0 +1,35 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// TODO(b/145815909): move StatsDimensionsValue.aidl and StatsLogEventWrapper.aidl here +filegroup { + name: "statsd_aidl", + srcs: ["**/*.aidl"], +} + +// This library is currently unused +aidl_interface { + name: "stats-event-parcel-aidl", + srcs: ["android/util/StatsEventParcel.aidl"], + backend: { + java: { + sdk_version: "28", + }, + cpp: { + enabled: false, + } + } +} diff --git a/core/java/android/os/IPullAtomCallback.aidl b/apex/statsd/aidl/android/os/IPullAtomCallback.aidl index 88d3c3e46ff5..88d3c3e46ff5 100644 --- a/core/java/android/os/IPullAtomCallback.aidl +++ b/apex/statsd/aidl/android/os/IPullAtomCallback.aidl diff --git a/core/java/android/os/IPullAtomResultReceiver.aidl b/apex/statsd/aidl/android/os/IPullAtomResultReceiver.aidl index bfb35ff0c9d1..00d026e25df3 100644 --- a/core/java/android/os/IPullAtomResultReceiver.aidl +++ b/apex/statsd/aidl/android/os/IPullAtomResultReceiver.aidl @@ -16,7 +16,7 @@ package android.os; -import android.util.StatsEvent; +import android.util.StatsEventParcel; /** * Binder interface to pull atoms for the stats service. @@ -27,6 +27,6 @@ interface IPullAtomResultReceiver { /** * Indicate that a pull request for an atom is complete. */ - oneway void pullFinished(int atomTag, boolean success, in StatsEvent[] output); + oneway void pullFinished(int atomTag, boolean success, in StatsEventParcel[] output); } diff --git a/core/java/android/os/IStatsCompanionService.aidl b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl index 22a25374e064..22a25374e064 100644 --- a/core/java/android/os/IStatsCompanionService.aidl +++ b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl diff --git a/core/java/android/os/IStatsManager.aidl b/apex/statsd/aidl/android/os/IStatsManager.aidl index 5ebb9f2e4e90..cc62f07a3750 100644 --- a/core/java/android/os/IStatsManager.aidl +++ b/apex/statsd/aidl/android/os/IStatsManager.aidl @@ -240,7 +240,7 @@ interface IStatsManager { * Logs an event for watchdog rollbacks. */ oneway void sendWatchdogRollbackOccurredAtom(in int rollbackType, in String packageName, - in long packageVersionCode); + in long packageVersionCode, in int rollbackReason, in String failingPackageName); /** * Returns the most recently registered experiment IDs. diff --git a/core/java/android/os/IStatsPullerCallback.aidl b/apex/statsd/aidl/android/os/IStatsPullerCallback.aidl index c3e1e55dde06..c3e1e55dde06 100644 --- a/core/java/android/os/IStatsPullerCallback.aidl +++ b/apex/statsd/aidl/android/os/IStatsPullerCallback.aidl diff --git a/apex/statsd/aidl/android/util/StatsEventParcel.aidl b/apex/statsd/aidl/android/util/StatsEventParcel.aidl new file mode 100644 index 000000000000..add8bfb47b1a --- /dev/null +++ b/apex/statsd/aidl/android/util/StatsEventParcel.aidl @@ -0,0 +1,8 @@ +package android.util; + +/** + * @hide + */ +parcelable StatsEventParcel { + byte[] buffer; +} diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index c9139b15f223..6fb3bc47859d 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -41,6 +41,7 @@ import android.app.AppOpsManager.HistoricalOps; import android.app.AppOpsManager.HistoricalOpsRequest; import android.app.AppOpsManager.HistoricalPackageOps; import android.app.AppOpsManager.HistoricalUidOps; +import android.app.INotificationManager; import android.app.ProcessMemoryState; import android.app.StatsManager; import android.bluetooth.BluetoothActivityEnergyInfo; @@ -139,6 +140,7 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemServiceManager; import com.android.server.am.MemoryStatUtil.MemoryStat; +import com.android.server.notification.NotificationManagerService; import com.android.server.role.RoleManagerInternal; import com.android.server.stats.IonMemoryUtil.IonAllocations; import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot; @@ -1750,14 +1752,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { if (statsFiles.size() != 1) { return; } - InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream( - statsFiles.get(0)); - int[] len = new int[1]; - byte[] stats = readFully(stream, len); - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, - wallClockNanos); - e.writeStorage(Arrays.copyOf(stats, len[0])); - pulledData.add(e); + unpackStreamedData(tagId, elapsedNanos, wallClockNanos, pulledData, statsFiles); new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark).delete(); new File( @@ -1773,6 +1768,52 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } + private INotificationManager mNotificationManager = + INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + + private void pullNotificationStats(int reportId, int tagId, long elapsedNanos, + long wallClockNanos, + List<StatsLogEventWrapper> pulledData) { + final long callingToken = Binder.clearCallingIdentity(); + try { + // determine last pull tine. Copy file trick from pullProcessStats? + long lastNotificationStatsNs = wallClockNanos - + TimeUnit.NANOSECONDS.convert(1, TimeUnit.DAYS); + + List<ParcelFileDescriptor> statsFiles = new ArrayList<>(); + long notificationStatsNs = mNotificationManager.pullStats( + lastNotificationStatsNs, reportId, true, statsFiles); + if (statsFiles.size() != 1) { + return; + } + unpackStreamedData(tagId, elapsedNanos, wallClockNanos, pulledData, statsFiles); + } catch (IOException e) { + Log.e(TAG, "Getting notistats failed: ", e); + + } catch (RemoteException e) { + Log.e(TAG, "Getting notistats failed: ", e); + } catch (SecurityException e) { + Log.e(TAG, "Getting notistats failed: ", e); + } finally { + Binder.restoreCallingIdentity(callingToken); + } + + } + + static void unpackStreamedData(int tagId, long elapsedNanos, long wallClockNanos, + List<StatsLogEventWrapper> pulledData, List<ParcelFileDescriptor> statsFiles) + throws IOException { + InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream( + statsFiles.get(0)); + int[] len = new int[1]; + byte[] stats = readFully(stream, len); + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, + wallClockNanos); + e.writeStorage(Arrays.copyOf(stats, len[0])); + pulledData.add(e); + } + static byte[] readFully(InputStream stream, int[] outLen) throws IOException { int pos = 0; final int initialAvail = stream.available(); @@ -2621,6 +2662,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullAppOps(elapsedNanos, wallClockNanos, ret); break; } + case StatsLog.NOTIFICATION_REMOTE_VIEWS: { + pullNotificationStats(NotificationManagerService.REPORT_REMOTE_VIEWS, + tagId, elapsedNanos, wallClockNanos, ret); + break; + } default: Slog.w(TAG, "No such tagId data as " + tagId); return null; diff --git a/api/current.txt b/api/current.txt index 3cf158dbf142..6b2f45ae118f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6834,7 +6834,7 @@ package android.app.admin { method public boolean removeOverrideApn(@NonNull android.content.ComponentName, int); method public boolean removeUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle); method public boolean requestBugreport(@NonNull android.content.ComponentName); - method public boolean resetPassword(String, int); + method @Deprecated public boolean resetPassword(String, int); method public boolean resetPasswordWithToken(@NonNull android.content.ComponentName, String, byte[], int); method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long); method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(@NonNull android.content.ComponentName); @@ -13453,6 +13453,7 @@ package android.drm { method public android.drm.DrmConvertedStatus closeConvertSession(int); method public android.drm.DrmConvertedStatus convertData(int, byte[]); method public String[] getAvailableDrmEngines(); + method @NonNull public java.util.Collection<android.drm.DrmSupportInfo> getAvailableDrmSupportInfo(); method public android.content.ContentValues getConstraints(String, int); method public android.content.ContentValues getConstraints(android.net.Uri, int); method public int getDrmObjectType(String, String); @@ -23277,6 +23278,8 @@ package android.location { method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback); method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback); method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback); + field public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED"; + field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED"; field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME"; field public static final String GPS_PROVIDER = "gps"; field public static final String KEY_LOCATION_CHANGED = "location"; @@ -25364,6 +25367,8 @@ package android.media { field public static final String KEY_COMPLEXITY = "complexity"; field public static final String KEY_CREATE_INPUT_SURFACE_SUSPENDED = "create-input-buffers-suspended"; field public static final String KEY_DURATION = "durationUs"; + field public static final String KEY_ENCODER_DELAY = "encoder-delay"; + field public static final String KEY_ENCODER_PADDING = "encoder-padding"; field public static final String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level"; field public static final String KEY_FRAME_RATE = "frame-rate"; field public static final String KEY_GRID_COLUMNS = "grid-cols"; @@ -25641,7 +25646,7 @@ package android.media { method public void onTracksFound(int); } - public static interface MediaParser.SeekMap { + public static final class MediaParser.SeekMap { method public long getDurationUs(); method @NonNull public android.util.Pair<android.media.MediaParser.SeekPoint,android.media.MediaParser.SeekPoint> getSeekPoints(long); method public boolean isSeekable(); @@ -38339,6 +38344,8 @@ package android.provider { public static final class ContactsContract.RawContacts implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.RawContactsColumns android.provider.ContactsContract.SyncColumns { method public static android.net.Uri getContactLookupUri(android.content.ContentResolver, android.net.Uri); + method @Nullable public static String getLocalAccountName(@NonNull android.content.Context); + method @Nullable public static String getLocalAccountType(@NonNull android.content.Context); method public static android.content.EntityIterator newEntityIterator(android.database.Cursor); field public static final int AGGREGATION_MODE_DEFAULT = 0; // 0x0 field public static final int AGGREGATION_MODE_DISABLED = 3; // 0x3 @@ -38905,6 +38912,7 @@ package android.provider { field public static final int MEDIA_TYPE_IMAGE = 1; // 0x1 field public static final int MEDIA_TYPE_NONE = 0; // 0x0 field public static final int MEDIA_TYPE_PLAYLIST = 4; // 0x4 + field public static final int MEDIA_TYPE_SUBTITLE = 5; // 0x5 field public static final int MEDIA_TYPE_VIDEO = 3; // 0x3 field public static final String MIME_TYPE = "mime_type"; field public static final String PARENT = "parent"; @@ -42824,6 +42832,7 @@ package android.system { method public static String[] listxattr(String) throws android.system.ErrnoException; method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException; method public static android.system.StructStat lstat(String) throws android.system.ErrnoException; + method @NonNull public static java.io.FileDescriptor memfd_create(@NonNull String, int) throws android.system.ErrnoException; method public static void mincore(long, long, byte[]) throws android.system.ErrnoException; method public static void mkdir(String, int) throws android.system.ErrnoException; method public static void mkfifo(String, int) throws android.system.ErrnoException; @@ -43132,6 +43141,7 @@ package android.system { field public static final int MCAST_UNBLOCK_SOURCE; field public static final int MCL_CURRENT; field public static final int MCL_FUTURE; + field public static final int MFD_CLOEXEC; field public static final int MSG_CTRUNC; field public static final int MSG_DONTROUTE; field public static final int MSG_EOR; @@ -44703,7 +44713,6 @@ package android.telephony { field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT = "opportunistic_network_entry_threshold_rssnr_int"; field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int"; field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int"; - field public static final String KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT = "parameters_use_for_5g_nr_signal_bar_int"; field public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool"; field public static final String KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL = "prevent_clir_activation_and_deactivation_code_bool"; field public static final String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array"; @@ -46529,12 +46538,12 @@ package android.telephony.mbms { package android.text { - public class AlteredCharSequence implements java.lang.CharSequence android.text.GetChars { - method public char charAt(int); - method public void getChars(int, int, char[], int); - method public int length(); - method public static android.text.AlteredCharSequence make(CharSequence, char[], int, int); - method public CharSequence subSequence(int, int); + @Deprecated public class AlteredCharSequence implements java.lang.CharSequence android.text.GetChars { + method @Deprecated public char charAt(int); + method @Deprecated public void getChars(int, int, char[], int); + method @Deprecated public int length(); + method @Deprecated public static android.text.AlteredCharSequence make(CharSequence, char[], int, int); + method @Deprecated public CharSequence subSequence(int, int); } @Deprecated public class AndroidCharacter { diff --git a/api/system-current.txt b/api/system-current.txt index c7bde93c61fd..6b51eabf6f34 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1331,8 +1331,22 @@ package android.app.usage { package android.bluetooth { public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile { + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void disableOptionalCodecs(@Nullable android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void enableOptionalCodecs(@Nullable android.bluetooth.BluetoothDevice); + method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothDevice getActiveDevice(); + method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothCodecStatus getCodecStatus(@Nullable android.bluetooth.BluetoothDevice); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int getOptionalCodecsEnabled(@Nullable android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setCodecConfigPreference(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothCodecConfig); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setOptionalCodecsEnabled(@Nullable android.bluetooth.BluetoothDevice, int); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int supportsOptionalCodecs(@Nullable android.bluetooth.BluetoothDevice); + field public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0; // 0x0 + field public static final int OPTIONAL_CODECS_PREF_DISABLED = 0; // 0x0 + field public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; // 0x1 + field public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1; // 0xffffffff + field public static final int OPTIONAL_CODECS_SUPPORTED = 1; // 0x1 + field public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1; // 0xffffffff } public final class BluetoothAdapter { @@ -1361,6 +1375,52 @@ package android.bluetooth { method public void onMetadataChanged(@NonNull android.bluetooth.BluetoothDevice, int, @Nullable byte[]); } + public final class BluetoothCodecConfig implements android.os.Parcelable { + ctor public BluetoothCodecConfig(int, int, int, int, int, long, long, long, long); + ctor public BluetoothCodecConfig(int); + method public int getBitsPerSample(); + method @NonNull public String getCodecName(); + method public int getCodecPriority(); + method public long getCodecSpecific1(); + method public int getCodecType(); + method public int getSampleRate(); + method public boolean isMandatoryCodec(); + field public static final int BITS_PER_SAMPLE_16 = 1; // 0x1 + field public static final int BITS_PER_SAMPLE_24 = 2; // 0x2 + field public static final int BITS_PER_SAMPLE_32 = 4; // 0x4 + field public static final int BITS_PER_SAMPLE_NONE = 0; // 0x0 + field public static final int CHANNEL_MODE_MONO = 1; // 0x1 + field public static final int CHANNEL_MODE_NONE = 0; // 0x0 + field public static final int CHANNEL_MODE_STEREO = 2; // 0x2 + field public static final int CODEC_PRIORITY_DEFAULT = 0; // 0x0 + field public static final int CODEC_PRIORITY_DISABLED = -1; // 0xffffffff + field public static final int CODEC_PRIORITY_HIGHEST = 1000000; // 0xf4240 + field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecConfig> CREATOR; + field public static final int SAMPLE_RATE_176400 = 16; // 0x10 + field public static final int SAMPLE_RATE_192000 = 32; // 0x20 + field public static final int SAMPLE_RATE_44100 = 1; // 0x1 + field public static final int SAMPLE_RATE_48000 = 2; // 0x2 + field public static final int SAMPLE_RATE_88200 = 4; // 0x4 + field public static final int SAMPLE_RATE_96000 = 8; // 0x8 + field public static final int SAMPLE_RATE_NONE = 0; // 0x0 + field public static final int SOURCE_CODEC_TYPE_AAC = 1; // 0x1 + field public static final int SOURCE_CODEC_TYPE_APTX = 2; // 0x2 + field public static final int SOURCE_CODEC_TYPE_APTX_HD = 3; // 0x3 + field public static final int SOURCE_CODEC_TYPE_INVALID = 1000000; // 0xf4240 + field public static final int SOURCE_CODEC_TYPE_LDAC = 4; // 0x4 + field public static final int SOURCE_CODEC_TYPE_MAX = 5; // 0x5 + field public static final int SOURCE_CODEC_TYPE_SBC = 0; // 0x0 + } + + public final class BluetoothCodecStatus implements android.os.Parcelable { + ctor public BluetoothCodecStatus(@Nullable android.bluetooth.BluetoothCodecConfig, @Nullable android.bluetooth.BluetoothCodecConfig[], @Nullable android.bluetooth.BluetoothCodecConfig[]); + method @Nullable public android.bluetooth.BluetoothCodecConfig getCodecConfig(); + method @Nullable public android.bluetooth.BluetoothCodecConfig[] getCodecsLocalCapabilities(); + method @Nullable public android.bluetooth.BluetoothCodecConfig[] getCodecsSelectableCapabilities(); + field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecStatus> CREATOR; + field public static final String EXTRA_CODEC_STATUS = "android.bluetooth.extra.CODEC_STATUS"; + } + public final class BluetoothDevice implements android.os.Parcelable { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess(); method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int); @@ -1626,9 +1686,25 @@ package android.content { field public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK"; field public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED"; field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME"; + field @Deprecated public static final String EXTRA_SIM_LOCKED_REASON = "reason"; + field @Deprecated public static final String EXTRA_SIM_STATE = "ss"; field public static final String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP"; field public static final String EXTRA_VERIFICATION_BUNDLE = "android.intent.extra.VERIFICATION_BUNDLE"; field public static final String METADATA_SETUP_VERSION = "android.SETUP_VERSION"; + field @Deprecated public static final String SIM_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED"; + field @Deprecated public static final String SIM_LOCKED_NETWORK = "NETWORK"; + field @Deprecated public static final String SIM_LOCKED_ON_PIN = "PIN"; + field @Deprecated public static final String SIM_LOCKED_ON_PUK = "PUK"; + field @Deprecated public static final String SIM_STATE_ABSENT = "ABSENT"; + field @Deprecated public static final String SIM_STATE_CARD_IO_ERROR = "CARD_IO_ERROR"; + field @Deprecated public static final String SIM_STATE_CARD_RESTRICTED = "CARD_RESTRICTED"; + field @Deprecated public static final String SIM_STATE_IMSI = "IMSI"; + field @Deprecated public static final String SIM_STATE_LOADED = "LOADED"; + field @Deprecated public static final String SIM_STATE_LOCKED = "LOCKED"; + field @Deprecated public static final String SIM_STATE_NOT_READY = "NOT_READY"; + field @Deprecated public static final String SIM_STATE_PRESENT = "PRESENT"; + field @Deprecated public static final String SIM_STATE_READY = "READY"; + field @Deprecated public static final String SIM_STATE_UNKNOWN = "UNKNOWN"; } public class IntentFilter implements android.os.Parcelable { @@ -1670,7 +1746,7 @@ package android.content.integrity { } public abstract class AtomicFormula implements android.content.integrity.Formula { - ctor public AtomicFormula(@android.content.integrity.AtomicFormula.Key int); + ctor public AtomicFormula(int); method public int getKey(); field public static final int APP_CERTIFICATE = 1; // 0x1 field public static final int EQ = 0; // 0x0 @@ -1686,7 +1762,7 @@ package android.content.integrity { } public static final class AtomicFormula.BooleanAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable { - ctor public AtomicFormula.BooleanAtomicFormula(@android.content.integrity.AtomicFormula.Key int, boolean); + ctor public AtomicFormula.BooleanAtomicFormula(int, boolean); method public int describeContents(); method public int getTag(); method public boolean getValue(); @@ -1696,7 +1772,7 @@ package android.content.integrity { } public static final class AtomicFormula.IntAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable { - ctor public AtomicFormula.IntAtomicFormula(@android.content.integrity.AtomicFormula.Key int, @android.content.integrity.AtomicFormula.Operator int, int); + ctor public AtomicFormula.IntAtomicFormula(int, int, int); method public int describeContents(); method public int getOperator(); method public int getTag(); @@ -1706,14 +1782,8 @@ package android.content.integrity { field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.AtomicFormula.IntAtomicFormula> CREATOR; } - @IntDef({android.content.integrity.AtomicFormula.PACKAGE_NAME, android.content.integrity.AtomicFormula.APP_CERTIFICATE, android.content.integrity.AtomicFormula.INSTALLER_NAME, android.content.integrity.AtomicFormula.INSTALLER_CERTIFICATE, android.content.integrity.AtomicFormula.VERSION_CODE, android.content.integrity.AtomicFormula.PRE_INSTALLED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AtomicFormula.Key { - } - - @IntDef({android.content.integrity.AtomicFormula.EQ, android.content.integrity.AtomicFormula.LT, android.content.integrity.AtomicFormula.LE, android.content.integrity.AtomicFormula.GT, android.content.integrity.AtomicFormula.GE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AtomicFormula.Operator { - } - public static final class AtomicFormula.StringAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable { - ctor public AtomicFormula.StringAtomicFormula(@android.content.integrity.AtomicFormula.Key int, @NonNull String, boolean); + ctor public AtomicFormula.StringAtomicFormula(int, @NonNull String, boolean); method public int describeContents(); method public boolean getIsHashedValue(); method public int getTag(); @@ -1724,9 +1794,9 @@ package android.content.integrity { } public final class CompoundFormula implements android.content.integrity.Formula android.os.Parcelable { - ctor public CompoundFormula(@android.content.integrity.CompoundFormula.Connector int, @NonNull java.util.List<android.content.integrity.Formula>); + ctor public CompoundFormula(int, @NonNull java.util.List<android.content.integrity.Formula>); method public int describeContents(); - method @android.content.integrity.CompoundFormula.Connector public int getConnector(); + method public int getConnector(); method @NonNull public java.util.List<android.content.integrity.Formula> getFormulas(); method public int getTag(); method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata); @@ -1737,11 +1807,8 @@ package android.content.integrity { field public static final int OR = 1; // 0x1 } - @IntDef({android.content.integrity.CompoundFormula.AND, android.content.integrity.CompoundFormula.OR, android.content.integrity.CompoundFormula.NOT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CompoundFormula.Connector { - } - public interface Formula { - method @android.content.integrity.Formula.Tag public int getTag(); + method public int getTag(); method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata); method @NonNull public static android.content.integrity.Formula readFromParcel(@NonNull android.os.Parcel); method public static void writeToParcel(@NonNull android.content.integrity.Formula, @NonNull android.os.Parcel, int); @@ -1751,13 +1818,10 @@ package android.content.integrity { field public static final int STRING_ATOMIC_FORMULA_TAG = 1; // 0x1 } - @IntDef({android.content.integrity.Formula.COMPOUND_FORMULA_TAG, android.content.integrity.Formula.STRING_ATOMIC_FORMULA_TAG, android.content.integrity.Formula.INT_ATOMIC_FORMULA_TAG, android.content.integrity.Formula.BOOLEAN_ATOMIC_FORMULA_TAG}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface Formula.Tag { - } - public final class Rule implements android.os.Parcelable { - ctor public Rule(@NonNull android.content.integrity.Formula, @android.content.integrity.Rule.Effect int); + ctor public Rule(@NonNull android.content.integrity.Formula, int); method public int describeContents(); - method @android.content.integrity.Rule.Effect public int getEffect(); + method public int getEffect(); method @NonNull public android.content.integrity.Formula getFormula(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.Rule> CREATOR; @@ -1765,9 +1829,6 @@ package android.content.integrity { field public static final int FORCE_ALLOW = 1; // 0x1 } - @IntDef({android.content.integrity.Rule.DENY, android.content.integrity.Rule.FORCE_ALLOW}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface Rule.Effect { - } - public class RuleSet { method @NonNull public java.util.List<android.content.integrity.Rule> getRules(); method @NonNull public String getVersion(); @@ -3868,16 +3929,19 @@ package android.media { method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups(); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); + method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAddress getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method public boolean isAudioServerRunning(); method public boolean isHdmiSystemAudioSupported(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removePreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException; method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException; method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy); method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAddress); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy); @@ -4048,9 +4112,11 @@ package android.media.audiopolicy { } public final class AudioProductStrategy implements android.os.Parcelable { + method @NonNull public static android.media.audiopolicy.AudioProductStrategy createInvalidAudioProductStrategy(int); method public int describeContents(); method @NonNull public android.media.AudioAttributes getAudioAttributes(); method public int getId(); + method public boolean supportsAudioAttributes(@NonNull android.media.AudioAttributes); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioProductStrategy> CREATOR; } @@ -4766,6 +4832,9 @@ package android.net.ipsec.ike { } public abstract class ChildSessionParams { + method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getLocalTrafficSelectors(); + method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getRemoteTrafficSelectors(); + method @NonNull public java.util.List<android.net.ipsec.ike.ChildSaProposal> getSaProposals(); } public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification { @@ -4833,6 +4902,13 @@ package android.net.ipsec.ike { } public final class IkeSessionParams { + method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getLocalAuthConfig(); + method @NonNull public android.net.ipsec.ike.IkeIdentification getLocalIdentification(); + method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getRemoteAuthConfig(); + method @NonNull public android.net.ipsec.ike.IkeIdentification getRemoteIdentification(); + method @NonNull public java.util.List<android.net.ipsec.ike.IkeSaProposal> getSaProposals(); + method @NonNull public java.net.InetAddress getServerAddress(); + method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket getUdpEncapsulationSocket(); } public static final class IkeSessionParams.Builder { @@ -4849,6 +4925,27 @@ package android.net.ipsec.ike { method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket); } + public abstract static class IkeSessionParams.IkeAuthConfig { + } + + public static class IkeSessionParams.IkeAuthDigitalSignLocalConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig { + method @NonNull public java.security.cert.X509Certificate getClientEndCertificate(); + method @NonNull public java.util.List<java.security.cert.X509Certificate> getIntermediateCertificates(); + method @NonNull public java.security.PrivateKey getPrivateKey(); + } + + public static class IkeSessionParams.IkeAuthDigitalSignRemoteConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig { + method @NonNull public java.security.cert.X509Certificate getRemoteCaCert(); + } + + public static class IkeSessionParams.IkeAuthEapConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig { + method @NonNull public android.net.eap.EapSessionConfig getEapConfig(); + } + + public static class IkeSessionParams.IkeAuthPskConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig { + method @NonNull public byte[] getPsk(); + } + public final class IkeTrafficSelector { ctor public IkeTrafficSelector(int, int, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress); field public final int endPort; @@ -4895,6 +4992,7 @@ package android.net.ipsec.ike { } public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams { + method @NonNull public java.util.List<android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest> getConfigurationRequests(); } public static final class TunnelModeChildSessionParams.Builder { @@ -4912,6 +5010,39 @@ package android.net.ipsec.ike { method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build(); } + public static interface TunnelModeChildSessionParams.ConfigRequest { + } + + public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest { + method @Nullable public java.net.Inet4Address getAddress(); + } + + public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest { + method @Nullable public java.net.Inet4Address getAddress(); + } + + public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest { + method @Nullable public java.net.Inet4Address getAddress(); + } + + public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Netmask extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest { + } + + public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Subnet extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest { + } + + public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest { + method @Nullable public java.net.Inet6Address getAddress(); + method public int getPrefixLength(); + } + + public static interface TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest { + method @Nullable public java.net.Inet6Address getAddress(); + } + + public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Subnet extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest { + } + } package android.net.ipsec.ike.exceptions { @@ -6075,6 +6206,7 @@ package android.os { } public class Binder implements android.os.IBinder { + method public int handleShellCommand(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.ParcelFileDescriptor, @NonNull android.os.ParcelFileDescriptor, @NonNull String[]); method public static void setProxyTransactListener(@Nullable android.os.Binder.ProxyTransactListener); } @@ -6623,7 +6755,7 @@ package android.os.connectivity { } public final class WifiActivityEnergyInfo implements android.os.Parcelable { - ctor public WifiActivityEnergyInfo(long, int, long, long, long, long, long); + ctor public WifiActivityEnergyInfo(long, int, long, long, long, long); method public int describeContents(); method public long getControllerEnergyUsedMicroJoules(); method public long getControllerIdleDurationMillis(); @@ -6670,6 +6802,14 @@ package android.os.connectivity { } +package android.os.ext { + + public class SdkExtensions { + method public static int getExtensionVersion(int); + } + +} + package android.os.image { public class DynamicSystemClient { @@ -6980,6 +7120,11 @@ package android.provider { field public static final int FLAG_REMOVABLE_USB = 524288; // 0x80000 } + public final class MediaStore { + method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static java.util.Set<java.lang.String> getRecentExternalVolumeNames(@NonNull android.content.Context); + method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException; + } + public abstract class SearchIndexableData { ctor public SearchIndexableData(); ctor public SearchIndexableData(android.content.Context); @@ -7237,6 +7382,10 @@ package android.provider { field public static final String SUB_ID = "sub_id"; } + public static final class Telephony.SimInfo { + field @NonNull public static final android.net.Uri CONTENT_URI; + } + public static final class Telephony.Sms.Intents { field public static final String ACTION_SMS_EMERGENCY_CB_RECEIVED = "android.provider.action.SMS_EMERGENCY_CB_RECEIVED"; } @@ -8419,14 +8568,6 @@ package android.telephony { field public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string"; } - public static final class CarrierConfigManager.Wifi { - field public static final String KEY_CARRIER_CONNECTION_MANAGER_PACKAGE_STRING = "wifi.carrier_connection_manager_package_string"; - field public static final String KEY_CARRIER_PROFILES_VERSION_INT = "wifi.carrier_profiles_version_int"; - field public static final String KEY_NETWORK_PROFILES_STRING_ARRAY = "wifi.network_profiles_string_array"; - field public static final String KEY_PASSPOINT_PROFILES_STRING_ARRAY = "wifi.passpoint_profiles_string_array"; - field public static final String KEY_PREFIX = "wifi."; - } - public final class CarrierRestrictionRules implements android.os.Parcelable { method @NonNull public java.util.List<java.lang.Boolean> areCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>); method public int describeContents(); @@ -8798,6 +8939,7 @@ package android.telephony { field public static final int UE_SECURITY_CAPABILITIES_MISMATCH = 2185; // 0x889 field public static final int UMTS_HANDOVER_TO_IWLAN = 2199; // 0x897 field public static final int UMTS_REACTIVATION_REQ = 39; // 0x27 + field public static final int UNACCEPTABLE_NETWORK_PARAMETER = 65538; // 0x10002 field public static final int UNACCEPTABLE_NON_EPS_AUTHENTICATION = 2187; // 0x88b field public static final int UNKNOWN = 65536; // 0x10000 field public static final int UNKNOWN_INFO_ELEMENT = 99; // 0x63 diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt index fcf5178716e1..9a6357572d36 100644 --- a/api/system-lint-baseline.txt +++ b/api/system-lint-baseline.txt @@ -196,7 +196,6 @@ ProtectedMember: android.service.contentcapture.ContentCaptureService#dump(java. ProtectedMember: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context): - SamShouldBeLast: android.accounts.AccountManager#addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler): SamShouldBeLast: android.accounts.AccountManager#addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean): diff --git a/api/test-current.txt b/api/test-current.txt index 3ce8c5ead4cb..efb85387a743 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1151,6 +1151,7 @@ package android.location { method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle); + field public static final String FUSED_PROVIDER = "fused"; } public final class LocationRequest implements android.os.Parcelable { @@ -2455,7 +2456,7 @@ package android.provider { method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException; method @NonNull public static java.io.File getVolumePath(@NonNull String) throws java.io.FileNotFoundException; - method @NonNull public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException; + method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException; method public static android.net.Uri scanFile(android.content.Context, java.io.File); method public static android.net.Uri scanFileFromShell(android.content.Context, java.io.File); method public static void scanVolume(android.content.Context, java.io.File); @@ -4437,7 +4438,7 @@ package android.view.accessibility { public final class AccessibilityManager { method public void addAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener, @Nullable android.os.Handler); - method @Nullable @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public String getAccessibilityShortcutService(); + method @NonNull @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public java.util.List<java.lang.String> getAccessibilityShortcutTargets(int); method @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public void performAccessibilityShortcut(); method public void removeAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener); } diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt index a8c4db38c841..ef8165fc6edb 100644 --- a/api/test-lint-baseline.txt +++ b/api/test-lint-baseline.txt @@ -2426,6 +2426,12 @@ ProtectedMember: android.view.View#resetResolvedDrawables(): ProtectedMember: android.view.ViewGroup#resetResolvedDrawables(): +PublicTypedef: android.os.HwParcel.Status: Don't expose @IntDef: @Status must be hidden. + +PublicTypedef: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability: Don't expose @IntDef: @MmTelCapability must be hidden. + +PublicTypedef: android.telephony.ims.feature.MmTelFeature.ProcessCallResult: Don't expose @IntDef: @ProcessCallResult must be hidden. + RawAidl: android.telephony.mbms.vendor.MbmsDownloadServiceBase: diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 17427a20b90e..484f82330055 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -250,6 +250,7 @@ cc_test { "tests/external/GpuStatsPuller_test.cpp", "tests/external/IncidentReportArgs_test.cpp", "tests/external/puller_util_test.cpp", + "tests/external/StatsCallbackPuller_test.cpp", "tests/external/StatsPuller_test.cpp", "tests/external/SurfaceflingerStatsPuller_test.cpp", "tests/FieldValue_test.cpp", diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index d10a661c6d83..3c5ad4231133 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -1417,7 +1417,10 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra Status StatsService::sendWatchdogRollbackOccurredAtom(const int32_t rollbackTypeIn, const android::String16& packageNameIn, - const int64_t packageVersionCodeIn) { + const int64_t packageVersionCodeIn, + const int32_t rollbackReasonIn, + const android::String16& + failingPackageNameIn) { // Note: We skip the usage stats op check here since we do not have a package name. // This is ok since we are overloading the usage_stats permission. // This method only sends data, it does not receive it. @@ -1439,7 +1442,8 @@ Status StatsService::sendWatchdogRollbackOccurredAtom(const int32_t rollbackType } android::util::stats_write(android::util::WATCHDOG_ROLLBACK_OCCURRED, - rollbackTypeIn, String8(packageNameIn).string(), packageVersionCodeIn); + rollbackTypeIn, String8(packageNameIn).string(), packageVersionCodeIn, + rollbackReasonIn, String8(failingPackageNameIn).string()); // Fast return to save disk read. if (rollbackTypeIn != android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 8c98e7b96936..50b1014f4e8a 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -214,7 +214,9 @@ public: virtual Status sendWatchdogRollbackOccurredAtom( const int32_t rollbackTypeIn, const android::String16& packageNameIn, - const int64_t packageVersionCodeIn) override; + const int64_t packageVersionCodeIn, + const int32_t rollbackReasonIn, + const android::String16& failingPackageNameIn) override; /** * Binder call to get registered experiment IDs. diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 2efb78943812..a20436d4bdda 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -112,9 +112,9 @@ message Atom { TouchEventReported touch_event_reported = 34; WakeupAlarmOccurred wakeup_alarm_occurred = 35; KernelWakeupReported kernel_wakeup_reported = 36; - WifiLockStateChanged wifi_lock_state_changed = 37; - WifiSignalStrengthChanged wifi_signal_strength_changed = 38; - WifiScanStateChanged wifi_scan_state_changed = 39; + WifiLockStateChanged wifi_lock_state_changed = 37 [(log_from_module) = "wifi"]; + WifiSignalStrengthChanged wifi_signal_strength_changed = 38 [(log_from_module) = "wifi"]; + WifiScanStateChanged wifi_scan_state_changed = 39 [(log_from_module) = "wifi"]; PhoneSignalStrengthChanged phone_signal_strength_changed = 40; SettingChanged setting_changed = 41; ActivityForegroundStateChanged activity_foreground_state_changed = 42; @@ -128,7 +128,7 @@ message Atom { AppStartFullyDrawn app_start_fully_drawn = 50; LmkKillOccurred lmk_kill_occurred = 51; PictureInPictureStateChanged picture_in_picture_state_changed = 52; - WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53; + WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53 [(log_from_module) = "wifi"]; LmkStateChanged lmk_state_changed = 54; AppStartMemoryStateCaptured app_start_memory_state_captured = 55; ShutdownSequenceReported shutdown_sequence_reported = 56; @@ -356,7 +356,7 @@ message Atom { } // Pulled events will start at field 10000. - // Next: 10065 + // Next: 10067 oneof pulled { WifiBytesTransfer wifi_bytes_transfer = 10000; WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001; @@ -423,6 +423,7 @@ message Atom { SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063; ProcessMemorySnapshot process_memory_snapshot = 10064; VmsClientStats vms_client_stats = 10065; + NotificationRemoteViews notification_remote_views = 10066; } // DO NOT USE field numbers above 100,000 in AOSP. @@ -1742,6 +1743,19 @@ message WatchdogRollbackOccurred { optional string package_name = 2; optional int32 package_version_code = 3; + + enum RollbackReasonType { + REASON_UNKNOWN = 0; + REASON_NATIVE_CRASH = 1; + REASON_EXPLICIT_HEALTH_CHECK = 2; + REASON_APP_CRASH = 3; + REASON_APP_NOT_RESPONDING = 4; + } + optional RollbackReasonType rollback_reason = 4; + + // Set by RollbackPackageHealthObserver to be the package that is failing when a rollback + // is initiated. Empty if the package is unknown. + optional string failing_package_name = 5; } /** @@ -4947,6 +4961,24 @@ message ProcStatsPkgProc { optional ProcessStatsSectionProto proc_stats_section = 1; } +// Next Tag: 2 +message PackageRemoteViewInfoProto { + optional string package_name = 1; + // add per-package additional info here (like channels) +} + +// Next Tag: 2 +message NotificationRemoteViewsProto { + repeated PackageRemoteViewInfoProto package_remote_view_info = 1; +} + +/** + * Pulled from NotificationManagerService.java + */ +message NotificationRemoteViews { + optional NotificationRemoteViewsProto notification_remote_views = 1; +} + message PowerProfileProto { optional double cpu_suspend = 1; @@ -5960,6 +5992,8 @@ message PermissionGrantRequestResultReported { IGNORED_RESTRICTED_PERMISSION = 9; // one time permission was granted by user action USER_GRANTED_ONE_TIME = 10; + // user ignored request by leaving the request screen without choosing any option + USER_IGNORED = 11; } // The result of the permission grant optional Result result = 6; @@ -7107,7 +7141,7 @@ message TextSelectionEvent { // Event type of this event. optional android.stats.textclassifier.EventType event_type = 2; - // Name of the model that is involved in this event. + // Name of the annotator model that is involved in this event. optional string model_name = 3; // Type of widget that was involved in triggering this event. @@ -7147,7 +7181,7 @@ message TextLinkifyEvent { // Event type of this event. optional android.stats.textclassifier.EventType event_type = 2; - // Name of the model that is involved in this event. + // Name of the annotator model that is involved in this event. optional string model_name = 3; // Type of widget that was involved in triggering this event. @@ -7187,7 +7221,7 @@ message ConversationActionsEvent { // Event type of this event. optional android.stats.textclassifier.EventType event_type = 2; - // Name of the model that is involved in this event. + // Name of the actions model that is involved in this event. optional string model_name = 3; // Type of widget that was involved in triggering this event. @@ -7207,6 +7241,9 @@ message ConversationActionsEvent { // Name of source package. optional string package_name = 9; + + // Name of the annotator model that is involved in this event. + optional string annotator_model_name = 10; } /** @@ -7221,7 +7258,7 @@ message LanguageDetectionEvent { // Event type of this event. optional android.stats.textclassifier.EventType event_type = 2; - // Name of the model that is involved in this event. + // Name of the language detection model that is involved in this event. optional string model_name = 3; // Type of widget that was involved in triggering this event. diff --git a/cmds/statsd/src/external/PullResultReceiver.cpp b/cmds/statsd/src/external/PullResultReceiver.cpp index 6bd05452f3b0..6b6fe7d9617f 100644 --- a/cmds/statsd/src/external/PullResultReceiver.cpp +++ b/cmds/statsd/src/external/PullResultReceiver.cpp @@ -25,12 +25,13 @@ namespace os { namespace statsd { PullResultReceiver::PullResultReceiver( - std::function<void(int32_t, bool, const vector<android::util::StatsEvent>&)> pullFinishCb) + std::function<void(int32_t, bool, const vector<android::util::StatsEventParcel>&)> + pullFinishCb) : pullFinishCallback(std::move(pullFinishCb)) { } Status PullResultReceiver::pullFinished(int32_t atomTag, bool success, - const vector<StatsEvent>& output) { + const vector<StatsEventParcel>& output) { pullFinishCallback(atomTag, success, output); return Status::ok(); } @@ -40,4 +41,4 @@ PullResultReceiver::~PullResultReceiver() { } // namespace statsd } // namespace os -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/cmds/statsd/src/external/PullResultReceiver.h b/cmds/statsd/src/external/PullResultReceiver.h index f731f778a337..17d06e4ff4db 100644 --- a/cmds/statsd/src/external/PullResultReceiver.h +++ b/cmds/statsd/src/external/PullResultReceiver.h @@ -24,7 +24,7 @@ namespace statsd { class PullResultReceiver : public BnPullAtomResultReceiver { public: - PullResultReceiver(function<void(int32_t, bool, const vector<android::util::StatsEvent>&)> + PullResultReceiver(function<void(int32_t, bool, const vector<android::util::StatsEventParcel>&)> pullFinishCallback); ~PullResultReceiver(); @@ -32,10 +32,11 @@ public: * Binder call for finishing a pull. */ binder::Status pullFinished(int32_t atomTag, bool success, - const vector<android::util::StatsEvent>& output) override; + const vector<android::util::StatsEventParcel>& output) override; private: - function<void(int32_t, bool, const vector<android::util::StatsEvent>&)> pullFinishCallback; + function<void(int32_t, bool, const vector<android::util::StatsEventParcel>&)> + pullFinishCallback; }; } // namespace statsd diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp index 92db68477dbd..0e6b677abb46 100644 --- a/cmds/statsd/src/external/StatsCallbackPuller.cpp +++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp @@ -20,7 +20,7 @@ #include "StatsCallbackPuller.h" #include <android/os/IPullAtomCallback.h> -#include <android/util/StatsEvent.h> +#include <android/util/StatsEventParcel.h> #include "PullResultReceiver.h" #include "StatsPullerManager.h" @@ -35,8 +35,9 @@ namespace android { namespace os { namespace statsd { -StatsCallbackPuller::StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback) - : StatsPuller(tagId), mCallback(callback) { +StatsCallbackPuller::StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback, + int64_t timeoutNs) + : StatsPuller(tagId), mCallback(callback), mTimeoutNs(timeoutNs) { VLOG("StatsCallbackPuller created for tag %d", tagId); } @@ -57,20 +58,26 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) { sp<PullResultReceiver> resultReceiver = new PullResultReceiver( [cv_mutex, cv, pullFinish, pullSuccess, sharedData]( - int32_t atomTag, bool success, const vector<StatsEvent>& output) { + int32_t atomTag, bool success, const vector<StatsEventParcel>& output) { // This is the result of the pull, executing in a statsd binder thread. // The pull could have taken a long time, and we should only modify // data (the output param) if the pointer is in scope and the pull did not time out. { lock_guard<mutex> lk(*cv_mutex); - // TODO: fill the shared vector of LogEvents once StatsEvent is complete. + for (const StatsEventParcel& parcel: output) { + shared_ptr<LogEvent> event = make_shared<LogEvent>( + const_cast<uint8_t*>(parcel.buffer.data()), parcel.buffer.size(), + /*uid=*/-1, /*useNewSchema=*/true); + sharedData->push_back(event); + } *pullSuccess = success; *pullFinish = true; } cv->notify_one(); }); - // Initiate the pull. + // Initiate the pull. This is a oneway call to a different process, except + // in unit tests. In process calls are not oneway. Status status = mCallback->onPullAtom(mTagId, resultReceiver); if (!status.isOk()) { return false; @@ -78,10 +85,8 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) { { unique_lock<mutex> unique_lk(*cv_mutex); - int64_t pullTimeoutNs = - StatsPullerManager::kAllPullAtomInfo.at({.atomTag = mTagId}).pullTimeoutNs; // Wait until the pull finishes, or until the pull timeout. - cv->wait_for(unique_lk, chrono::nanoseconds(pullTimeoutNs), + cv->wait_for(unique_lk, chrono::nanoseconds(mTimeoutNs), [pullFinish] { return *pullFinish; }); if (!*pullFinish) { // Note: The parent stats puller will also note that there was a timeout and that the @@ -90,7 +95,7 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) { return true; } else { // Only copy the data if we did not timeout and the pull was successful. - if (pullSuccess) { + if (*pullSuccess) { *data = std::move(*sharedData); } VLOG("StatsCallbackPuller::pull succeeded for %d", mTagId); diff --git a/cmds/statsd/src/external/StatsCallbackPuller.h b/cmds/statsd/src/external/StatsCallbackPuller.h index ce506c7f9785..d943f9d189c5 100644 --- a/cmds/statsd/src/external/StatsCallbackPuller.h +++ b/cmds/statsd/src/external/StatsCallbackPuller.h @@ -27,11 +27,17 @@ namespace statsd { class StatsCallbackPuller : public StatsPuller { public: - explicit StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback); + explicit StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback, + int64_t timeoutNs); private: bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override; const sp<IPullAtomCallback> mCallback; + const int64_t mTimeoutNs; + + FRIEND_TEST(StatsCallbackPullerTest, PullFail); + FRIEND_TEST(StatsCallbackPullerTest, PullSuccess); + FRIEND_TEST(StatsCallbackPullerTest, PullTimeout); }; } // namespace statsd diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index b5bad0530503..9ee627efa841 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -281,6 +281,9 @@ std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {{.atomTag = android::util::VMS_CLIENT_STATS}, {.additiveFields = {5, 6, 7, 8, 9, 10}, .puller = new CarStatsPuller(android::util::VMS_CLIENT_STATS)}}, + // NotiifcationRemoteViews. + {{.atomTag = android::util::NOTIFICATION_REMOTE_VIEWS}, + {.puller = new StatsCompanionServicePuller(android::util::NOTIFICATION_REMOTE_VIEWS)}}, }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { @@ -497,10 +500,11 @@ void StatsPullerManager::RegisterPullAtomCallback(const int uid, const int32_t a VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag); // TODO: linkToDeath with the callback so that we can remove it and delete the puller. StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true); - kAllPullAtomInfo[{.atomTag = atomTag}] = {.additiveFields = additiveFields, - .coolDownNs = coolDownNs, - .puller = new StatsCallbackPuller(atomTag, callback), - .pullTimeoutNs = timeoutNs, + kAllPullAtomInfo[{.atomTag = atomTag}] = { + .additiveFields = additiveFields, + .coolDownNs = coolDownNs, + .puller = new StatsCallbackPuller(atomTag, callback, timeoutNs), + .pullTimeoutNs = timeoutNs, }; } diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index 67022a078b01..36f4623c4dcb 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -52,6 +52,17 @@ LogEvent::LogEvent(uint8_t* msg, uint32_t len, uint32_t uid) #endif } +LogEvent::LogEvent(uint8_t* msg, uint32_t len, uint32_t uid, bool useNewSchema) + : mBuf(msg), mRemainingLen(len), mLogdTimestampNs(time(nullptr)), mLogUid(uid) { + if (useNewSchema) { + initNew(); + } else { + mContext = create_android_log_parser((char*)msg, len); + init(mContext); + if (mContext) android_log_destroy(&mContext); // set mContext to NULL + } +} + LogEvent::LogEvent(const LogEvent& event) { mTagId = event.mTagId; mLogUid = event.mLogUid; diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h index 1ff95f7240ac..596d623debe5 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -75,6 +75,11 @@ public: explicit LogEvent(uint8_t* msg, uint32_t len, uint32_t uid); /** + * Temp constructor to use for pulled atoms until we flip the socket schema. + */ + explicit LogEvent(uint8_t* msg, uint32_t len, uint32_t uid, bool useNewSchema); + + /** * Creates LogEvent from StatsLogEventWrapper. */ static void createLogEvents(const StatsLogEventWrapper& statsLogEventWrapper, diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index eb78ebc521e1..2c9991125d89 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -159,7 +159,7 @@ ValueMetricProducer::ValueMetricProducer( // Kicks off the puller immediately if condition is true and diff based. if (mIsActive && mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) { - pullAndMatchEventsLocked(mCurrentBucketStartTimeNs, mCondition); + pullAndMatchEventsLocked(mCurrentBucketStartTimeNs); } // Now that activations are processed, start the condition timer if needed. mConditionTimer.onConditionChanged(mIsActive && mCondition == ConditionState::kTrue, @@ -183,11 +183,9 @@ void ValueMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition void ValueMetricProducer::dropDataLocked(const int64_t dropTimeNs) { StatsdStats::getInstance().noteBucketDropped(mMetricId); - // We are going to flush the data without doing a pull first so we need to invalidte the data. - bool pullNeeded = mIsPulled && mCondition == ConditionState::kTrue; - if (pullNeeded) { - invalidateCurrentBucket(); - } + + // The current partial bucket is not flushed and does not require a pull, + // so the data is still valid. flushIfNeededLocked(dropTimeNs); clearPastBucketsLocked(dropTimeNs); } @@ -216,7 +214,7 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, invalidateCurrentBucket(); break; case NO_TIME_CONSTRAINTS: - pullAndMatchEventsLocked(dumpTimeNs, mCondition); + pullAndMatchEventsLocked(dumpTimeNs); break; } } @@ -366,7 +364,7 @@ void ValueMetricProducer::onActiveStateChangedLocked(const int64_t& eventTimeNs) // Pull on active state changes. if (!isEventTooLate) { if (mIsPulled) { - pullAndMatchEventsLocked(eventTimeNs, mCondition); + pullAndMatchEventsLocked(eventTimeNs); } // When active state changes from true to false, clear diff base but don't // reset other counters as we may accumulate more value in the bucket. @@ -425,7 +423,7 @@ void ValueMetricProducer::onConditionChangedLocked(const bool condition, // called before #onDataPulled. if (mIsPulled && (newCondition == ConditionState::kTrue || mCondition == ConditionState::kTrue)) { - pullAndMatchEventsLocked(eventTimeNs, newCondition); + pullAndMatchEventsLocked(eventTimeNs); } // For metrics that use diff, when condition changes from true to false, @@ -443,8 +441,7 @@ void ValueMetricProducer::onConditionChangedLocked(const bool condition, mConditionTimer.onConditionChanged(mCondition, eventTimeNs); } -void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs, - ConditionState condition) { +void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) { vector<std::shared_ptr<LogEvent>> allData; if (!mPullerManager->Pull(mPullTagId, &allData)) { ALOGE("Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs); @@ -452,7 +449,7 @@ void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs, return; } - accumulateEvents(allData, timestampNs, timestampNs, condition); + accumulateEvents(allData, timestampNs, timestampNs); } int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTimeNs) { @@ -474,7 +471,7 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven if (isEventLate) { // If the event is late, we are in the middle of a bucket. Just // process the data without trying to snap the data to the nearest bucket. - accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs, mCondition); + accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs); } else { // For scheduled pulled data, the effective event time is snap to the nearest // bucket end. In the case of waking up from a deep sleep state, we will @@ -488,7 +485,7 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1; StatsdStats::getInstance().noteBucketBoundaryDelayNs( mMetricId, originalPullTimeNs - bucketEndTime); - accumulateEvents(allData, originalPullTimeNs, bucketEndTime, mCondition); + accumulateEvents(allData, originalPullTimeNs, bucketEndTime); } } } @@ -499,8 +496,7 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven } void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData, - int64_t originalPullTimeNs, int64_t eventElapsedTimeNs, - ConditionState condition) { + int64_t originalPullTimeNs, int64_t eventElapsedTimeNs) { bool isEventLate = eventElapsedTimeNs < mCurrentBucketStartTimeNs; if (isEventLate) { VLOG("Skip bucket end pull due to late arrival: %lld vs %lld", diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 206e602dd1c7..2033a2a0cd02 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -78,7 +78,7 @@ public: return; } if (mIsPulled && mCondition) { - pullAndMatchEventsLocked(eventTimeNs, mCondition); + pullAndMatchEventsLocked(eventTimeNs); } flushCurrentBucketLocked(eventTimeNs, eventTimeNs); }; @@ -188,11 +188,10 @@ private: bool hitFullBucketGuardRailLocked(const MetricDimensionKey& newKey); - void pullAndMatchEventsLocked(const int64_t timestampNs, ConditionState condition); + void pullAndMatchEventsLocked(const int64_t timestampNs); void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData, - int64_t originalPullTimeNs, int64_t eventElapsedTimeNs, - ConditionState condition); + int64_t originalPullTimeNs, int64_t eventElapsedTimeNs); ValueBucket buildPartialBucket(int64_t bucketEndTime, const std::vector<Interval>& intervals); diff --git a/cmds/statsd/src/state/StateManager.cpp b/cmds/statsd/src/state/StateManager.cpp index 2fa28c9846fd..80d398339ebb 100644 --- a/cmds/statsd/src/state/StateManager.cpp +++ b/cmds/statsd/src/state/StateManager.cpp @@ -29,18 +29,15 @@ StateManager& StateManager::getInstance() { } void StateManager::onLogEvent(const LogEvent& event) { - std::lock_guard<std::mutex> lock(mMutex); if (mStateTrackers.find(event.GetTagId()) != mStateTrackers.end()) { mStateTrackers[event.GetTagId()]->onLogEvent(event); } } bool StateManager::registerListener(int32_t atomId, wp<StateListener> listener) { - std::lock_guard<std::mutex> lock(mMutex); - - // Check if state tracker already exists + // Check if state tracker already exists. if (mStateTrackers.find(atomId) == mStateTrackers.end()) { - // Create a new state tracker iff atom is a state atom + // Create a new state tracker iff atom is a state atom. auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find(atomId); if (it != android::util::AtomsInfo::kStateAtomsFieldOptions.end()) { mStateTrackers[atomId] = new StateTracker(atomId, it->second); @@ -79,8 +76,6 @@ void StateManager::unregisterListener(int32_t atomId, wp<StateListener> listener bool StateManager::getStateValue(int32_t atomId, const HashableDimensionKey& key, FieldValue* output) const { - std::lock_guard<std::mutex> lock(mMutex); - auto it = mStateTrackers.find(atomId); if (it != mStateTrackers.end()) { return it->second->getStateValue(key, output); diff --git a/cmds/statsd/src/state/StateManager.h b/cmds/statsd/src/state/StateManager.h index 272724ceeb08..a6053e6f317e 100644 --- a/cmds/statsd/src/state/StateManager.h +++ b/cmds/statsd/src/state/StateManager.h @@ -27,6 +27,10 @@ namespace android { namespace os { namespace statsd { +/** + * This class is NOT thread safe. + * It should only be used while StatsLogProcessor's lock is held. + */ class StateManager : public virtual RefBase { public: StateManager(){}; @@ -56,13 +60,10 @@ public: FieldValue* output) const; inline int getStateTrackersCount() const { - std::lock_guard<std::mutex> lock(mMutex); return mStateTrackers.size(); } inline int getListenersCount(int32_t atomId) const { - std::lock_guard<std::mutex> lock(mMutex); - auto it = mStateTrackers.find(atomId); if (it != mStateTrackers.end()) { return it->second->getListenersCount(); @@ -71,10 +72,10 @@ public: } private: - mutable std::mutex mMutex; + mutable std::mutex mMutex; - // Maps state atom ids to StateTrackers - std::unordered_map<int32_t, sp<StateTracker>> mStateTrackers; + // Maps state atom ids to StateTrackers + std::unordered_map<int32_t, sp<StateTracker>> mStateTrackers; }; } // namespace statsd diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp index 90ce1e90142e..ef59c9242cb2 100644 --- a/cmds/statsd/src/state/StateTracker.cpp +++ b/cmds/statsd/src/state/StateTracker.cpp @@ -139,6 +139,13 @@ void StateTracker::handlePartialReset(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey) { VLOG("StateTracker handle partial reset"); if (mStateMap.find(primaryKey) != mStateMap.end()) { + for (auto l : mListeners) { + auto sl = l.promote(); + if (sl != nullptr) { + sl->onStateChanged(eventTimeNs, mAtomId, primaryKey, + mStateMap.find(primaryKey)->second.state, mDefaultState); + } + } mStateMap.erase(primaryKey); } } diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h index 544857f06711..e65325a52b98 100644 --- a/cmds/statsd/src/state/StateTracker.h +++ b/cmds/statsd/src/state/StateTracker.h @@ -80,10 +80,12 @@ private: // Set of all StateListeners (objects listening for state changes) std::set<wp<StateListener>> mListeners; - // Reset all state values in map to default state + // Reset all state values in map to default state. void handleReset(const int64_t eventTimeNs); - // Reset only the state value mapped to primary key to default state + // Reset only the state value mapped to the given primary key to default state. + // Partial resets are used when we only need to update the state of one primary + // key instead of clearing/reseting every key in the map. void handlePartialReset(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey); // Update the StateMap based on the received state value. diff --git a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp new file mode 100644 index 000000000000..2b0590d11f54 --- /dev/null +++ b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp @@ -0,0 +1,210 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/external/StatsCallbackPuller.h" + +#include <android/os/BnPullAtomCallback.h> +#include <android/os/IPullAtomResultReceiver.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <stdio.h> + +#include <chrono> +#include <thread> +#include <vector> + +#include "../metrics/metrics_test_helper.h" +#include "src/stats_log_util.h" +#include "tests/statsd_test_util.h" + +#ifdef __ANDROID__ + +namespace android { +namespace os { +namespace statsd { + +using namespace testing; +using std::make_shared; +using std::shared_ptr; +using std::vector; +using std::this_thread::sleep_for; +using testing::Contains; + +namespace { +int pullTagId = -12; +bool pullSuccess; +vector<int64_t> values; +int64_t pullDelayNs; +int64_t pullTimeoutNs; +int64_t pullCoolDownNs; +std::thread pullThread; + +stats_event* createSimpleEvent(int64_t value) { + stats_event* event = stats_event_obtain(); + stats_event_set_atom_id(event, pullTagId); + stats_event_write_int64(event, value); + stats_event_build(event); + return event; +} + +void executePull(const sp<IPullAtomResultReceiver>& resultReceiver) { + // Convert stats_events into StatsEventParcels. + std::vector<android::util::StatsEventParcel> parcels; + for (int i = 0; i < values.size(); i++) { + stats_event* event = createSimpleEvent(values[i]); + size_t size; + uint8_t* buffer = stats_event_get_buffer(event, &size); + + android::util::StatsEventParcel p; + // vector.assign() creates a copy, but this is inevitable unless + // stats_event.h/c uses a vector as opposed to a buffer. + p.buffer.assign(buffer, buffer + size); + parcels.push_back(std::move(p)); + stats_event_release(event); + } + + sleep_for(std::chrono::nanoseconds(pullDelayNs)); + resultReceiver->pullFinished(pullTagId, pullSuccess, parcels); +} + +class FakePullAtomCallback : public BnPullAtomCallback { +public: + binder::Status onPullAtom(int atomTag, + const sp<IPullAtomResultReceiver>& resultReceiver) override { + // Force pull to happen in separate thread to simulate binder. + pullThread = std::thread(executePull, resultReceiver); + return binder::Status::ok(); + } +}; + +class StatsCallbackPullerTest : public ::testing::Test { +public: + StatsCallbackPullerTest() { + } + + void SetUp() override { + pullSuccess = false; + pullDelayNs = 0; + values.clear(); + pullTimeoutNs = 10000000000LL; // 10 seconds. + pullCoolDownNs = 1000000000; // 1 second. + } + + void TearDown() override { + if (pullThread.joinable()) { + pullThread.join(); + } + values.clear(); + } +}; +} // Anonymous namespace. + +TEST_F(StatsCallbackPullerTest, PullSuccess) { + sp<FakePullAtomCallback> cb = new FakePullAtomCallback(); + int64_t value = 43; + pullSuccess = true; + values.push_back(value); + + StatsCallbackPuller puller(pullTagId, cb, pullTimeoutNs); + + vector<std::shared_ptr<LogEvent>> dataHolder; + int64_t startTimeNs = getElapsedRealtimeNs(); + EXPECT_TRUE(puller.PullInternal(&dataHolder)); + int64_t endTimeNs = getElapsedRealtimeNs(); + + EXPECT_EQ(1, dataHolder.size()); + EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId()); + EXPECT_LT(startTimeNs, dataHolder[0]->GetElapsedTimestampNs()); + EXPECT_GT(endTimeNs, dataHolder[0]->GetElapsedTimestampNs()); + EXPECT_EQ(1, dataHolder[0]->size()); + EXPECT_EQ(value, dataHolder[0]->getValues()[0].mValue.int_value); +} + +TEST_F(StatsCallbackPullerTest, PullFail) { + sp<FakePullAtomCallback> cb = new FakePullAtomCallback(); + pullSuccess = false; + int64_t value = 1234; + values.push_back(value); + + StatsCallbackPuller puller(pullTagId, cb, pullTimeoutNs); + + vector<std::shared_ptr<LogEvent>> dataHolder; + EXPECT_FALSE(puller.PullInternal(&dataHolder)); + EXPECT_EQ(0, dataHolder.size()); +} + +TEST_F(StatsCallbackPullerTest, PullTimeout) { + sp<FakePullAtomCallback> cb = new FakePullAtomCallback(); + pullSuccess = true; + pullDelayNs = 500000000; // 500ms. + pullTimeoutNs = 10000; // 10 microseconds. + int64_t value = 4321; + values.push_back(value); + + StatsCallbackPuller puller(pullTagId, cb, pullTimeoutNs); + + vector<std::shared_ptr<LogEvent>> dataHolder; + int64_t startTimeNs = getElapsedRealtimeNs(); + // Returns true to let StatsPuller code evaluate the timeout. + EXPECT_TRUE(puller.PullInternal(&dataHolder)); + int64_t endTimeNs = getElapsedRealtimeNs(); + int64_t actualPullDurationNs = endTimeNs - startTimeNs; + + // Pull should take at least the timeout amount of time, but should stop early because the delay + // is bigger. + EXPECT_LT(pullTimeoutNs, actualPullDurationNs); + EXPECT_GT(pullDelayNs, actualPullDurationNs); + EXPECT_EQ(0, dataHolder.size()); + + // Let the pull return and make sure that the dataHolder is not modified. + pullThread.join(); + EXPECT_EQ(0, dataHolder.size()); +} + +// Register a puller and ensure that the timeout logic works. +TEST_F(StatsCallbackPullerTest, RegisterAndTimeout) { + sp<FakePullAtomCallback> cb = new FakePullAtomCallback(); + pullSuccess = true; + pullDelayNs = 500000000; // 500 ms. + pullTimeoutNs = 10000; // 10 microsseconds. + int64_t value = 4321; + values.push_back(value); + + StatsPullerManager pullerManager; + pullerManager.RegisterPullAtomCallback(/*uid=*/-1, pullTagId, pullCoolDownNs, pullTimeoutNs, + vector<int32_t>(), cb); + vector<std::shared_ptr<LogEvent>> dataHolder; + int64_t startTimeNs = getElapsedRealtimeNs(); + // Returns false, since StatsPuller code will evaluate the timeout. + EXPECT_FALSE(pullerManager.Pull(pullTagId, &dataHolder)); + int64_t endTimeNs = getElapsedRealtimeNs(); + int64_t actualPullDurationNs = endTimeNs - startTimeNs; + + // Pull should take at least the timeout amount of time, but should stop early because the delay + // is bigger. + EXPECT_LT(pullTimeoutNs, actualPullDurationNs); + EXPECT_GT(pullDelayNs, actualPullDurationNs); + EXPECT_EQ(0, dataHolder.size()); + + // Let the pull return and make sure that the dataHolder is not modified. + pullThread.join(); + EXPECT_EQ(0, dataHolder.size()); +} + +} // namespace statsd +} // namespace os +} // namespace android +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif diff --git a/cmds/statsd/tests/external/StatsPuller_test.cpp b/cmds/statsd/tests/external/StatsPuller_test.cpp index 76e2097a90b8..c40719a17f62 100644 --- a/cmds/statsd/tests/external/StatsPuller_test.cpp +++ b/cmds/statsd/tests/external/StatsPuller_test.cpp @@ -35,6 +35,7 @@ using std::vector; using std::this_thread::sleep_for; using testing::Contains; +namespace { // cooldown time 1sec. int pullTagId = 10014; @@ -76,7 +77,9 @@ public: } }; -TEST_F(StatsPullerTest, PullSucces) { +} // Anonymous namespace. + +TEST_F(StatsPullerTest, PullSuccess) { pullData.push_back(createSimpleEvent(1111L, 33)); pullSuccess = true; diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp index 1173d57e5e3f..3a260639de0f 100644 --- a/cmds/uiautomator/library/Android.bp +++ b/cmds/uiautomator/library/Android.bp @@ -22,6 +22,7 @@ droiddoc { "android.test.runner", "junit", "android.test.base", + "unsupportedappusage", ], custom_template: "droiddoc-templates-sdk", installable: false, diff --git a/config/preloaded-classes b/config/preloaded-classes index 0394a7a489ba..97f009c09217 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -878,7 +878,7 @@ android.content.pm.-$$Lambda$jpya2qgMDDEok2GAoKRDqPM5lIE android.content.pm.ActivityInfo$1 android.content.pm.ActivityInfo$WindowLayout android.content.pm.ActivityInfo -android.content.pm.AndroidHidlUpdater +android.content.pm.parsing.library.AndroidHidlUpdater android.content.pm.ApplicationInfo$1 android.content.pm.ApplicationInfo android.content.pm.BaseParceledListSlice @@ -922,10 +922,10 @@ android.content.pm.LauncherApps$1 android.content.pm.LauncherApps android.content.pm.ModuleInfo$1 android.content.pm.ModuleInfo -android.content.pm.OrgApacheHttpLegacyUpdater -android.content.pm.PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater -android.content.pm.PackageBackwardCompatibility$RemoveUnnecessaryAndroidTestBaseLibrary -android.content.pm.PackageBackwardCompatibility +android.content.pm.parsing.library.OrgApacheHttpLegacyUpdater +android.content.pm.parsing.library.PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater +android.content.pm.parsing.library.PackageBackwardCompatibility$RemoveUnnecessaryAndroidTestBaseLibrary +android.content.pm.parsing.library.PackageBackwardCompatibility android.content.pm.PackageInfo$1 android.content.pm.PackageInfo android.content.pm.PackageInstaller$Session @@ -960,7 +960,7 @@ android.content.pm.PackageParser$SigningDetails$1 android.content.pm.PackageParser$SigningDetails android.content.pm.PackageParser$SplitNameComparator android.content.pm.PackageParser -android.content.pm.PackageSharedLibraryUpdater +android.content.pm.parsing.library.PackageSharedLibraryUpdater android.content.pm.PackageStats$1 android.content.pm.PackageStats android.content.pm.PackageUserState diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java index f4cadfd8bbc1..d79740b49b3d 100644 --- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java @@ -141,6 +141,16 @@ public final class AccessibilityShortcutInfo { } /** + * The {@link ComponentName} of the accessibility shortcut target. + * + * @return The component name + */ + @NonNull + public ComponentName getComponentName() { + return mComponentName; + } + + /** * The localized summary of the accessibility shortcut target. * * @return The localized summary if available, and {@code null} if a summary diff --git a/core/java/android/annotation/Hide.java b/core/java/android/annotation/Hide.java new file mode 100644 index 000000000000..c8e5a4a97ae7 --- /dev/null +++ b/core/java/android/annotation/Hide.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.annotation; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PACKAGE; +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that an API is hidden by default, in a similar fashion to the + * <pre>@hide</pre> javadoc tag. + * + * <p>Note that, in order for this to work, metalava has to be invoked with + * the flag {@code --hide-annotation android.annotation.Hide}. + * @hide + */ +@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE}) +@Retention(RetentionPolicy.CLASS) +public @interface Hide { +} diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 6bea68b446a4..577272e38707 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -726,7 +726,7 @@ public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, - Window.OnWindowDismissedCallback, WindowControllerCallback, + Window.OnWindowDismissedCallback, AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient { private static final String TAG = "Activity"; private static final boolean DEBUG_LIFECYCLE = false; @@ -938,6 +938,62 @@ public class Activity extends ContextThemeWrapper private Boolean mLastDispatchedIsInMultiWindowMode; private Boolean mLastDispatchedIsInPictureInPictureMode; + private final WindowControllerCallback mWindowControllerCallback = + new WindowControllerCallback() { + /** + * Moves the activity between {@link WindowConfiguration#WINDOWING_MODE_FREEFORM} windowing + * mode and {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}. + * + * @hide + */ + @Override + public void toggleFreeformWindowingMode() throws RemoteException { + ActivityTaskManager.getService().toggleFreeformWindowingMode(mToken); + } + + /** + * Puts the activity in picture-in-picture mode if the activity supports. + * @see android.R.attr#supportsPictureInPicture + * @hide + */ + @Override + public void enterPictureInPictureModeIfPossible() { + if (mActivityInfo.supportsPictureInPicture()) { + enterPictureInPictureMode(); + } + } + + @Override + public boolean isTaskRoot() { + try { + return ActivityTaskManager.getService().getTaskForActivity(mToken, true) >= 0; + } catch (RemoteException e) { + return false; + } + } + + /** + * Update the forced status bar color. + * @hide + */ + @Override + public void updateStatusBarColor(int color) { + mTaskDescription.setStatusBarColor(color); + setTaskDescription(mTaskDescription); + } + + /** + * Update the forced navigation bar color. + * @hide + */ + @Override + public void updateNavigationBarColor(int color) { + mTaskDescription.setNavigationBarColor(color); + setTaskDescription(mTaskDescription); + } + + }; + private static native String getDlWarning(); /** Return the intent that started this activity. */ @@ -3915,49 +3971,6 @@ public class Activity extends ContextThemeWrapper /** - * Moves the activity between {@link WindowConfiguration#WINDOWING_MODE_FREEFORM} windowing mode - * and {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}. - * - * @hide - */ - @Override - public void toggleFreeformWindowingMode() throws RemoteException { - ActivityTaskManager.getService().toggleFreeformWindowingMode(mToken); - } - - /** - * Update the forced status bar color. - * @hide - */ - @Override - public void updateStatusBarColor(int color) { - mTaskDescription.setStatusBarColor(color); - setTaskDescription(mTaskDescription); - } - - /** - * Update the forced navigation bar color. - * @hide - */ - @Override - public void updateNavigationBarColor(int color) { - mTaskDescription.setNavigationBarColor(color); - setTaskDescription(mTaskDescription); - } - - /** - * Puts the activity in picture-in-picture mode if the activity supports. - * @see android.R.attr#supportsPictureInPicture - * @hide - */ - @Override - public void enterPictureInPictureModeIfPossible() { - if (mActivityInfo.supportsPictureInPicture()) { - enterPictureInPictureMode(); - } - } - - /** * Called to process key events. You can override this to intercept all * key events before they are dispatched to the window. Be sure to call * this implementation for key events that should be handled normally. @@ -6603,13 +6616,8 @@ public class Activity extends ContextThemeWrapper * * @return True if this is the root activity, else false. */ - @Override public boolean isTaskRoot() { - try { - return ActivityTaskManager.getService().getTaskForActivity(mToken, true) >= 0; - } catch (RemoteException e) { - return false; - } + return mWindowControllerCallback.isTaskRoot(); } /** @@ -7801,7 +7809,7 @@ public class Activity extends ContextThemeWrapper mFragments.attachHost(null /*parent*/); mWindow = new PhoneWindow(this, window, activityConfigCallback); - mWindow.setWindowControllerCallback(this); + mWindow.setWindowControllerCallback(mWindowControllerCallback); mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 35a48a82cd5e..49a8e2f3f816 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -6254,6 +6254,7 @@ public final class ActivityThread extends ClientTransactionHandler { // send up app name; do this *before* waiting for debugger Process.setArgV0(data.processName); android.ddm.DdmHandleAppName.setAppName(data.processName, + data.appInfo.packageName, UserHandle.myUserId()); VMRuntime.setProcessPackageName(data.appInfo.packageName); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 5032f776f8f0..f2fa4fd6845c 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -2008,7 +2008,7 @@ public class AppOpsManager { false, // WRITE_MEDIA_VIDEO false, // READ_MEDIA_IMAGES false, // WRITE_MEDIA_IMAGES - false, // LEGACY_STORAGE + true, // LEGACY_STORAGE false, // ACCESS_ACCESSIBILITY false, // READ_DEVICE_IDENTIFIERS false, // ACCESS_MEDIA_LOCATION diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl index d3d7c68d0992..254657e26f3a 100644 --- a/core/java/android/app/IBackupAgent.aidl +++ b/core/java/android/app/IBackupAgent.aidl @@ -84,6 +84,19 @@ oneway interface IBackupAgent { long appVersionCode, in ParcelFileDescriptor newState, int token, IBackupManager callbackBinder); + /** + * Restore an entire data snapshot to the application and pass the list of excluded keys to the + * backup agent. + * + * @param excludedKeys List of keys to be excluded from the restore. It will be passed to the + * backup agent to make it aware of what data has been removed (in case it has any + * application-level implications) as well as the data that should be removed by the + * agent itself. + */ + void doRestoreWithExcludedKeys(in ParcelFileDescriptor data, + long appVersionCode, in ParcelFileDescriptor newState, + int token, IBackupManager callbackBinder, in List<String> excludedKeys); + /** * Perform a "full" backup to the given file descriptor. The output file is presumed * to be a socket or other non-seekable, write-only data sink. When this method is diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 0957dba4eac1..86f52af1a13b 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -207,4 +207,6 @@ interface INotificationManager void setPrivateNotificationsAllowed(boolean allow); boolean getPrivateNotificationsAllowed(); + + long pullStats(long startNs, int report, boolean doAgg, out List<ParcelFileDescriptor> stats); } diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index 588aceecf4d8..690e9567c1ef 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -493,6 +493,7 @@ public class Instrumentation { public Activity startActivitySync(@NonNull Intent intent, @Nullable Bundle options) { validateNotAppThread(); + final Activity activity; synchronized (mSync) { intent = new Intent(intent); @@ -527,16 +528,18 @@ public class Instrumentation { } catch (InterruptedException e) { } } while (mWaitingActivities.contains(aw)); + activity = aw.activity; + } - waitForEnterAnimationComplete(aw.activity); + // Do not call this method within mSync, lest it could block the main thread. + waitForEnterAnimationComplete(activity); - // Apply an empty transaction to ensure SF has a chance to update before - // the Activity is ready (b/138263890). - try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) { - t.apply(true); - } - return aw.activity; + // Apply an empty transaction to ensure SF has a chance to update before + // the Activity is ready (b/138263890). + try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) { + t.apply(true); } + return activity; } /** diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java index 2ef05105825a..90cd51f8649f 100644 --- a/core/java/android/app/StatsManager.java +++ b/core/java/android/app/StatsManager.java @@ -34,6 +34,7 @@ import android.os.ServiceManager; import android.util.AndroidException; import android.util.Slog; import android.util.StatsEvent; +import android.util.StatsEventParcel; import com.android.internal.annotations.GuardedBy; @@ -540,10 +541,12 @@ public final class StatsManager { mExecutor.execute(() -> { List<StatsEvent> data = new ArrayList<>(); boolean success = mCallback.onPullAtom(atomTag, data); - StatsEvent[] arr = new StatsEvent[data.size()]; - arr = data.toArray(arr); + StatsEventParcel[] parcels = new StatsEventParcel[data.size()]; + for (int i = 0; i < data.size(); i++) { + parcels[i].buffer = data.get(i).getBytes(); + } try { - resultReceiver.pullFinished(atomTag, success, arr); + resultReceiver.pullFinished(atomTag, success, parcels); } catch (RemoteException e) { Slog.w(TAG, "StatsPullResultReceiver failed for tag " + mAtomId); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 34ceb08f39bf..915e4572c035 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -3742,17 +3742,35 @@ public class DevicePolicyManager { /** * Force a new password for device unlock (the password needed to access the entire device) or * the work profile challenge on the current user. This takes effect immediately. - * <p> - * <em>For device owner and profile owners targeting SDK level - * {@link android.os.Build.VERSION_CODES#O} or above, this API is no longer available and will - * throw {@link SecurityException}. Please use the new API {@link #resetPasswordWithToken} - * instead. </em> - * <p> - * <em>Note: This API has been limited as of {@link android.os.Build.VERSION_CODES#N} for - * device admins that are not device owner and not profile owner. - * The password can now only be changed if there is currently no password set. Device owner - * and profile owner can still do this when user is unlocked and does not have a managed - * profile.</em> + * + * <p> Before {@link android.os.Build.VERSION_CODES#N}, this API is available to device admin, + * profile owner and device owner. Starting from {@link android.os.Build.VERSION_CODES#N}, + * legacy device admin (who is not also profile owner or device owner) can only call this + * API to set a new password if there is currently no password set. Profile owner and device + * owner can continue to force change an existing password as long as the target user is + * unlocked, although device owner will not be able to call this API at all if there is also a + * managed profile on the device. + * + * <p> Between {@link android.os.Build.VERSION_CODES#O}, + * {@link android.os.Build.VERSION_CODES#P} and {@link android.os.Build.VERSION_CODES#Q}, + * profile owner and devices owner targeting SDK level {@link android.os.Build.VERSION_CODES#O} + * or above who attempt to call this API will receive {@link SecurityException}; they are + * encouraged to migrate to the new {@link #resetPasswordWithToken} API instead. + * Profile owner and device owner targeting older SDK levels are not affected: they continue + * to experience the existing behaviour described in the previous paragraph. + * + * <p><em>Starting from {@link android.os.Build.VERSION_CODES#R}, this API is no longer + * supported in most cases.</em> Device owner and profile owner calling + * this API will receive {@link SecurityException} if they target SDK level + * {@link android.os.Build.VERSION_CODES#O} or above, or they will receive a silent failure + * (API returning {@code false}) if they target lower SDK level. + * For legacy device admins, this API throws {@link SecurityException} if they target SDK level + * {@link android.os.Build.VERSION_CODES#N} or above, and returns {@code false} otherwise. Only + * privileged apps holding RESET_PASSWORD permission which are part of + * the system factory image can still call this API to set a new password if there is currently + * no password set. In this case, if the device already has a password, this API will throw + * {@link SecurityException}. + * * <p> * The given password must be sufficient for the current password quality and length constraints * as returned by {@link #getPasswordQuality(ComponentName)} and @@ -3760,12 +3778,7 @@ public class DevicePolicyManager { * it will be rejected and false returned. Note that the password may be a stronger quality * (containing alphanumeric characters when the requested quality is only numeric), in which * case the currently active quality will be increased to match. - * <p> - * Calling with a null or empty password will clear any existing PIN, pattern or password if the - * current password constraints allow it. <em>Note: This will not work in - * {@link android.os.Build.VERSION_CODES#N} and later for managed profiles, or for device admins - * that are not device owner or profile owner. Once set, the password cannot be changed to null - * or empty except by these admins.</em> + * * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, this * methods does nothing. * <p> @@ -3777,11 +3790,13 @@ public class DevicePolicyManager { * @param flags May be 0 or combination of {@link #RESET_PASSWORD_REQUIRE_ENTRY} and * {@link #RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT}. * @return Returns true if the password was applied, or false if it is not acceptable for the - * current constraints or if the user has not been decrypted yet. + * current constraints. * @throws SecurityException if the calling application does not own an active administrator * that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} * @throws IllegalStateException if the calling user is locked or has a managed profile. + * @deprecated Please use {@link #resetPasswordWithToken} instead. */ + @Deprecated @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) public boolean resetPassword(String password, int flags) { throwIfParentInstance("resetPassword"); @@ -5555,7 +5570,12 @@ public class DevicePolicyManager { * device, for this user. After setting this, no applications running as this user will be able * to access any cameras on the device. * <p> - * If the caller is device owner, then the restriction will be applied to all users. + * This method can be called on the {@link DevicePolicyManager} instance, + * returned by {@link #getParentProfileInstance(ComponentName)}, where the caller must be + * the profile owner of an organization-owned managed profile. + * <p> + * If the caller is device owner or called on the parent instance, then the + * restriction will be applied to all users. * <p> * The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA} to be able to call this method; if it has @@ -5567,10 +5587,9 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA}. */ public void setCameraDisabled(@NonNull ComponentName admin, boolean disabled) { - throwIfParentInstance("setCameraDisabled"); if (mService != null) { try { - mService.setCameraDisabled(admin, disabled); + mService.setCameraDisabled(admin, disabled, mParentInstance); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -5580,11 +5599,15 @@ public class DevicePolicyManager { /** * Determine whether or not the device's cameras have been disabled for this user, * either by the calling admin, if specified, or all admins. + * <p> + * This method can be called on the {@link DevicePolicyManager} instance, + * returned by {@link #getParentProfileInstance(ComponentName)}, where the caller must be + * the profile owner of an organization-owned managed profile. + * * @param admin The name of the admin component to check, or {@code null} to check whether any admins * have disabled the camera */ public boolean getCameraDisabled(@Nullable ComponentName admin) { - throwIfParentInstance("getCameraDisabled"); return getCameraDisabled(admin, myUserId()); } @@ -5593,7 +5616,7 @@ public class DevicePolicyManager { public boolean getCameraDisabled(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getCameraDisabled(admin, userHandle); + return mService.getCameraDisabled(admin, userHandle, mParentInstance); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -7893,7 +7916,8 @@ public class DevicePolicyManager { * for the list of keys. * @throws SecurityException if {@code admin} is not a device or profile owner. */ - public void addUserRestriction(@NonNull ComponentName admin, String key) { + public void addUserRestriction(@NonNull ComponentName admin, + @UserManager.UserRestrictionKey String key) { throwIfParentInstance("addUserRestriction"); if (mService != null) { try { @@ -7915,7 +7939,8 @@ public class DevicePolicyManager { * for the list of keys. * @throws SecurityException if {@code admin} is not a device or profile owner. */ - public void clearUserRestriction(@NonNull ComponentName admin, String key) { + public void clearUserRestriction(@NonNull ComponentName admin, + @UserManager.UserRestrictionKey String key) { throwIfParentInstance("clearUserRestriction"); if (mService != null) { try { @@ -9344,7 +9369,6 @@ public class DevicePolicyManager { * <li>{@link #setPasswordExpirationTimeout}</li> * <li>{@link #getPasswordExpiration}</li> * <li>{@link #getPasswordMaximumLength}</li> - * <li>{@link #getPasswordComplexity}</li> * <li>{@link #isActivePasswordSufficient}</li> * <li>{@link #getCurrentFailedPasswordAttempts}</li> * <li>{@link #getMaximumFailedPasswordsForWipe}</li> @@ -9359,6 +9383,14 @@ public class DevicePolicyManager { * <li>{@link #getRequiredStrongAuthTimeout}</li> * <li>{@link #setRequiredStrongAuthTimeout}</li> * </ul> + * <p> + * The following methods are supported for the parent instance but can only be called by the + * profile owner of a managed profile that was created during the device provisioning flow: + * <ul> + * <li>{@link #getPasswordComplexity}</li> + * <li>{@link #setCameraDisabled}</li> + * <li>{@link #getCameraDisabled}</li> + * </ul> * * <p>The following methods can be called by the profile owner of a managed profile * on an organization-owned device: diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java index 713126ee9341..f299d456a18f 100644 --- a/core/java/android/app/admin/DevicePolicyManagerInternal.java +++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java @@ -145,15 +145,6 @@ public abstract class DevicePolicyManagerInternal { public abstract void reportSeparateProfileChallengeChanged(@UserIdInt int userId); /** - * Check whether the user could have their password reset in an untrusted manor due to there - * being an admin which can call {@link #resetPassword} to reset the password without knowledge - * of the previous password. - * - * @param userId The user in question - */ - public abstract boolean canUserHaveUntrustedCredentialReset(@UserIdInt int userId); - - /** * Return text of error message if printing is disabled. * Called by Print Service when printing is disabled by PO or DO when printing is attempted. * diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index f55026c76906..34246fa808bd 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -114,8 +114,8 @@ interface IDevicePolicyManager { boolean requestBugreport(in ComponentName who); - void setCameraDisabled(in ComponentName who, boolean disabled); - boolean getCameraDisabled(in ComponentName who, int userHandle); + void setCameraDisabled(in ComponentName who, boolean disabled, boolean parent); + boolean getCameraDisabled(in ComponentName who, int userHandle, boolean parent); void setScreenCaptureDisabled(in ComponentName who, boolean disabled); boolean getScreenCaptureDisabled(in ComponentName who, int userHandle); diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 24580b40aa29..20aa0647d261 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -45,7 +45,10 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.util.Collections; +import java.util.HashSet; import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -327,6 +330,28 @@ public abstract class BackupAgent extends ContextWrapper { } /** + * New version of {@link #onRestore(BackupDataInput, long, android.os.ParcelFileDescriptor)} + * that has a list of keys to be excluded from the restore. Key/value pairs for which the key + * is present in {@code excludedKeys} have already been excluded from the restore data by the + * system. The list is passed to the agent to make it aware of what data has been removed (in + * case it has any application-level consequences) as well as the data that should be removed + * by the agent itself. + * + * The default implementation calls {@link #onRestore(BackupDataInput, long, + * android.os.ParcelFileDescriptor)}. + * + * @param excludedKeys A list of keys to be excluded from restore. + * + * @hide + */ + public void onRestore(BackupDataInput data, long appVersionCode, + ParcelFileDescriptor newState, + Set<String> excludedKeys) + throws IOException { + onRestore(data, appVersionCode, newState); + } + + /** * The application is having its entire file system contents backed up. {@code data} * points to the backup destination, and the app has the opportunity to choose which * files are to be stored. To commit a file as part of the backup, call the @@ -1016,8 +1041,22 @@ public abstract class BackupAgent extends ContextWrapper { @Override public void doRestore(ParcelFileDescriptor data, long appVersionCode, - ParcelFileDescriptor newState, - int token, IBackupManager callbackBinder) throws RemoteException { + ParcelFileDescriptor newState, int token, IBackupManager callbackBinder) + throws RemoteException { + doRestoreInternal(data, appVersionCode, newState, token, callbackBinder, + /* excludedKeys */ null); + } + + @Override + public void doRestoreWithExcludedKeys(ParcelFileDescriptor data, long appVersionCode, + ParcelFileDescriptor newState, int token, IBackupManager callbackBinder, + List<String> excludedKeys) throws RemoteException { + doRestoreInternal(data, appVersionCode, newState, token, callbackBinder, excludedKeys); + } + + private void doRestoreInternal(ParcelFileDescriptor data, long appVersionCode, + ParcelFileDescriptor newState, int token, IBackupManager callbackBinder, + List<String> excludedKeys) throws RemoteException { // Ensure that we're running with the app's normal permission level long ident = Binder.clearCallingIdentity(); @@ -1029,7 +1068,9 @@ public abstract class BackupAgent extends ContextWrapper { BackupDataInput input = new BackupDataInput(data.getFileDescriptor()); try { - BackupAgent.this.onRestore(input, appVersionCode, newState); + BackupAgent.this.onRestore(input, appVersionCode, newState, + excludedKeys != null ? new HashSet<>(excludedKeys) + : Collections.emptySet()); } catch (IOException ex) { Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex); throw new RuntimeException(ex); diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 8ed61b6c87e3..64df0e84f6dc 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -17,6 +17,7 @@ package android.bluetooth; import android.Manifest; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -32,6 +33,8 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; @@ -154,13 +157,22 @@ public final class BluetoothA2dp implements BluetoothProfile { */ public static final int STATE_NOT_PLAYING = 11; + /** @hide */ + @IntDef(prefix = "OPTIONAL_CODECS_", value = { + OPTIONAL_CODECS_SUPPORT_UNKNOWN, + OPTIONAL_CODECS_NOT_SUPPORTED, + OPTIONAL_CODECS_SUPPORTED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface OptionalCodecsSupportStatus {} + /** * We don't have a stored preference for whether or not the given A2DP sink device supports * optional codecs. * * @hide */ - @UnsupportedAppUsage + @SystemApi public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1; /** @@ -168,7 +180,7 @@ public final class BluetoothA2dp implements BluetoothProfile { * * @hide */ - @UnsupportedAppUsage + @SystemApi public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0; /** @@ -176,16 +188,25 @@ public final class BluetoothA2dp implements BluetoothProfile { * * @hide */ - @UnsupportedAppUsage + @SystemApi public static final int OPTIONAL_CODECS_SUPPORTED = 1; + /** @hide */ + @IntDef(prefix = "OPTIONAL_CODECS_PREF_", value = { + OPTIONAL_CODECS_PREF_UNKNOWN, + OPTIONAL_CODECS_PREF_DISABLED, + OPTIONAL_CODECS_PREF_ENABLED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface OptionalCodecsPreferenceStatus {} + /** - * We don't have a stored preference for whether optional codecs should be enabled or disabled - * for the given A2DP device. + * We don't have a stored preference for whether optional codecs should be enabled or + * disabled for the given A2DP device. * * @hide */ - @UnsupportedAppUsage + @SystemApi public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1; /** @@ -193,7 +214,7 @@ public final class BluetoothA2dp implements BluetoothProfile { * * @hide */ - @UnsupportedAppUsage + @SystemApi public static final int OPTIONAL_CODECS_PREF_DISABLED = 0; /** @@ -201,7 +222,7 @@ public final class BluetoothA2dp implements BluetoothProfile { * * @hide */ - @UnsupportedAppUsage + @SystemApi public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; private BluetoothAdapter mAdapter; @@ -248,13 +269,12 @@ public final class BluetoothA2dp implements BluetoothProfile { * the state. Users can get the connection state of the profile * from this intent. * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} - * permission. * * @param device Remote Bluetooth Device * @return false on immediate error, true otherwise * @hide */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) @UnsupportedAppUsage public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); @@ -289,13 +309,12 @@ public final class BluetoothA2dp implements BluetoothProfile { * {@link #STATE_DISCONNECTING} can be used to distinguish between the * two scenarios. * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} - * permission. * * @param device Remote Bluetooth Device * @return false on immediate error, true otherwise * @hide */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) @UnsupportedAppUsage public boolean disconnect(BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); @@ -384,14 +403,12 @@ public final class BluetoothA2dp implements BluetoothProfile { * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted * with the active device. * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} - * permission. - * * @param device the remote Bluetooth device. Could be null to clear * the active device and stop streaming audio to a Bluetooth device. * @return false on immediate error, true otherwise * @hide */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) @UnsupportedAppUsage public boolean setActiveDevice(@Nullable BluetoothDevice device) { if (DBG) log("setActiveDevice(" + device + ")"); @@ -412,16 +429,13 @@ public final class BluetoothA2dp implements BluetoothProfile { /** * Get the connected device that is active. * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH} - * permission. - * * @return the connected device that is active or null if no device * is active * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @SystemApi @Nullable - @UnsupportedAppUsage + @RequiresPermission(Manifest.permission.BLUETOOTH) public BluetoothDevice getActiveDevice() { if (VDBG) log("getActiveDevice()"); try { @@ -441,7 +455,7 @@ public final class BluetoothA2dp implements BluetoothProfile { * Set priority of the profile * * <p> The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, + * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF} * * @param device Paired bluetooth device * @param priority @@ -626,8 +640,10 @@ public final class BluetoothA2dp implements BluetoothProfile { * @return the current codec status * @hide */ - @UnsupportedAppUsage - public @Nullable BluetoothCodecStatus getCodecStatus(BluetoothDevice device) { + @SystemApi + @Nullable + @RequiresPermission(Manifest.permission.BLUETOOTH) + public BluetoothCodecStatus getCodecStatus(@Nullable BluetoothDevice device) { if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")"); try { final IBluetoothA2dp service = getService(); @@ -652,9 +668,10 @@ public final class BluetoothA2dp implements BluetoothProfile { * @param codecConfig the codec configuration preference * @hide */ - @UnsupportedAppUsage - public void setCodecConfigPreference(BluetoothDevice device, - BluetoothCodecConfig codecConfig) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public void setCodecConfigPreference(@Nullable BluetoothDevice device, + @Nullable BluetoothCodecConfig codecConfig) { if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")"); try { final IBluetoothA2dp service = getService(); @@ -676,8 +693,9 @@ public final class BluetoothA2dp implements BluetoothProfile { * active A2DP Bluetooth device. * @hide */ - @UnsupportedAppUsage - public void enableOptionalCodecs(BluetoothDevice device) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public void enableOptionalCodecs(@Nullable BluetoothDevice device) { if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")"); enableDisableOptionalCodecs(device, true); } @@ -689,8 +707,9 @@ public final class BluetoothA2dp implements BluetoothProfile { * active A2DP Bluetooth device. * @hide */ - @UnsupportedAppUsage - public void disableOptionalCodecs(BluetoothDevice device) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public void disableOptionalCodecs(@Nullable BluetoothDevice device) { if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")"); enableDisableOptionalCodecs(device, false); } @@ -728,8 +747,10 @@ public final class BluetoothA2dp implements BluetoothProfile { * OPTIONAL_CODECS_SUPPORTED. * @hide */ - @UnsupportedAppUsage - public int supportsOptionalCodecs(BluetoothDevice device) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @OptionalCodecsSupportStatus + public int supportsOptionalCodecs(@Nullable BluetoothDevice device) { try { final IBluetoothA2dp service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { @@ -738,7 +759,7 @@ public final class BluetoothA2dp implements BluetoothProfile { if (service == null) Log.w(TAG, "Proxy not attached to service"); return OPTIONAL_CODECS_SUPPORT_UNKNOWN; } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e); + Log.e(TAG, "Error talking to BT service in supportsOptionalCodecs()", e); return OPTIONAL_CODECS_SUPPORT_UNKNOWN; } } @@ -751,8 +772,10 @@ public final class BluetoothA2dp implements BluetoothProfile { * OPTIONAL_CODECS_PREF_DISABLED. * @hide */ - @UnsupportedAppUsage - public int getOptionalCodecsEnabled(BluetoothDevice device) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @OptionalCodecsPreferenceStatus + public int getOptionalCodecsEnabled(@Nullable BluetoothDevice device) { try { final IBluetoothA2dp service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { @@ -761,7 +784,7 @@ public final class BluetoothA2dp implements BluetoothProfile { if (service == null) Log.w(TAG, "Proxy not attached to service"); return OPTIONAL_CODECS_PREF_UNKNOWN; } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e); + Log.e(TAG, "Error talking to BT service in getOptionalCodecsEnabled()", e); return OPTIONAL_CODECS_PREF_UNKNOWN; } } @@ -775,8 +798,10 @@ public final class BluetoothA2dp implements BluetoothProfile { * OPTIONAL_CODECS_PREF_DISABLED. * @hide */ - @UnsupportedAppUsage - public void setOptionalCodecsEnabled(BluetoothDevice device, int value) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public void setOptionalCodecsEnabled(@Nullable BluetoothDevice device, + @OptionalCodecsPreferenceStatus int value) { try { if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java index c17834aa8e52..cf3367602aa9 100755 --- a/core/java/android/bluetooth/BluetoothA2dpSink.java +++ b/core/java/android/bluetooth/BluetoothA2dpSink.java @@ -320,7 +320,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile { * Set priority of the profile * * <p> The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, + * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF} * * @param device Paired bluetooth device * @param priority diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 9b5280d48f45..3f8cb627e382 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -862,18 +862,7 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean isEnabled() { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isEnabled(); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - - return false; + return getState() == BluetoothAdapter.STATE_ON; } /** diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java index 36f3a1eeba79..08d0797997b5 100644 --- a/core/java/android/bluetooth/BluetoothCodecConfig.java +++ b/core/java/android/bluetooth/BluetoothCodecConfig.java @@ -16,10 +16,15 @@ package android.bluetooth; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** @@ -29,78 +34,131 @@ import java.util.Objects; * * {@hide} */ +@SystemApi public final class BluetoothCodecConfig implements Parcelable { // Add an entry for each source codec here. // NOTE: The values should be same as those listed in the following file: // hardware/libhardware/include/hardware/bt_av.h - @UnsupportedAppUsage + + /** @hide */ + @IntDef(prefix = "SOURCE_CODEC_TYPE_", value = { + SOURCE_CODEC_TYPE_SBC, + SOURCE_CODEC_TYPE_AAC, + SOURCE_CODEC_TYPE_APTX, + SOURCE_CODEC_TYPE_APTX_HD, + SOURCE_CODEC_TYPE_LDAC, + SOURCE_CODEC_TYPE_MAX, + SOURCE_CODEC_TYPE_INVALID + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SourceCodecType {} + public static final int SOURCE_CODEC_TYPE_SBC = 0; - @UnsupportedAppUsage + public static final int SOURCE_CODEC_TYPE_AAC = 1; - @UnsupportedAppUsage + public static final int SOURCE_CODEC_TYPE_APTX = 2; - @UnsupportedAppUsage + public static final int SOURCE_CODEC_TYPE_APTX_HD = 3; - @UnsupportedAppUsage + public static final int SOURCE_CODEC_TYPE_LDAC = 4; - @UnsupportedAppUsage + public static final int SOURCE_CODEC_TYPE_MAX = 5; - @UnsupportedAppUsage + public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000; - @UnsupportedAppUsage + /** @hide */ + @IntDef(prefix = "CODEC_PRIORITY_", value = { + CODEC_PRIORITY_DISABLED, + CODEC_PRIORITY_DEFAULT, + CODEC_PRIORITY_HIGHEST + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CodecPriority {} + public static final int CODEC_PRIORITY_DISABLED = -1; - @UnsupportedAppUsage + public static final int CODEC_PRIORITY_DEFAULT = 0; - @UnsupportedAppUsage + public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000; - @UnsupportedAppUsage + + /** @hide */ + @IntDef(prefix = "SAMPLE_RATE_", value = { + SAMPLE_RATE_NONE, + SAMPLE_RATE_44100, + SAMPLE_RATE_48000, + SAMPLE_RATE_88200, + SAMPLE_RATE_96000, + SAMPLE_RATE_176400, + SAMPLE_RATE_192000 + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SampleRate {} + public static final int SAMPLE_RATE_NONE = 0; - @UnsupportedAppUsage + public static final int SAMPLE_RATE_44100 = 0x1 << 0; - @UnsupportedAppUsage + public static final int SAMPLE_RATE_48000 = 0x1 << 1; - @UnsupportedAppUsage + public static final int SAMPLE_RATE_88200 = 0x1 << 2; - @UnsupportedAppUsage + public static final int SAMPLE_RATE_96000 = 0x1 << 3; - @UnsupportedAppUsage + public static final int SAMPLE_RATE_176400 = 0x1 << 4; - @UnsupportedAppUsage + public static final int SAMPLE_RATE_192000 = 0x1 << 5; - @UnsupportedAppUsage + + /** @hide */ + @IntDef(prefix = "BITS_PER_SAMPLE_", value = { + BITS_PER_SAMPLE_NONE, + BITS_PER_SAMPLE_16, + BITS_PER_SAMPLE_24, + BITS_PER_SAMPLE_32 + }) + @Retention(RetentionPolicy.SOURCE) + public @interface BitsPerSample {} + public static final int BITS_PER_SAMPLE_NONE = 0; - @UnsupportedAppUsage + public static final int BITS_PER_SAMPLE_16 = 0x1 << 0; - @UnsupportedAppUsage + public static final int BITS_PER_SAMPLE_24 = 0x1 << 1; - @UnsupportedAppUsage + public static final int BITS_PER_SAMPLE_32 = 0x1 << 2; - @UnsupportedAppUsage + + /** @hide */ + @IntDef(prefix = "CHANNEL_MODE_", value = { + CHANNEL_MODE_NONE, + CHANNEL_MODE_MONO, + CHANNEL_MODE_STEREO + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ChannelMode {} + public static final int CHANNEL_MODE_NONE = 0; - @UnsupportedAppUsage + public static final int CHANNEL_MODE_MONO = 0x1 << 0; - @UnsupportedAppUsage + public static final int CHANNEL_MODE_STEREO = 0x1 << 1; - private final int mCodecType; - private int mCodecPriority; - private final int mSampleRate; - private final int mBitsPerSample; - private final int mChannelMode; + private final @SourceCodecType int mCodecType; + private @CodecPriority int mCodecPriority; + private final @SampleRate int mSampleRate; + private final @BitsPerSample int mBitsPerSample; + private final @ChannelMode int mChannelMode; private final long mCodecSpecific1; private final long mCodecSpecific2; private final long mCodecSpecific3; private final long mCodecSpecific4; - @UnsupportedAppUsage - public BluetoothCodecConfig(int codecType, int codecPriority, - int sampleRate, int bitsPerSample, - int channelMode, long codecSpecific1, + public BluetoothCodecConfig(@SourceCodecType int codecType, @CodecPriority int codecPriority, + @SampleRate int sampleRate, @BitsPerSample int bitsPerSample, + @ChannelMode int channelMode, long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) { mCodecType = codecType; @@ -114,8 +172,7 @@ public final class BluetoothCodecConfig implements Parcelable { mCodecSpecific4 = codecSpecific4; } - @UnsupportedAppUsage - public BluetoothCodecConfig(int codecType) { + public BluetoothCodecConfig(@SourceCodecType int codecType) { mCodecType = codecType; mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE; @@ -144,6 +201,12 @@ public final class BluetoothCodecConfig implements Parcelable { return false; } + /** + * Returns a hash based on the config values + * + * @return a hash based on the config values + * @hide + */ @Override public int hashCode() { return Objects.hash(mCodecType, mCodecPriority, mSampleRate, @@ -155,6 +218,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Checks whether the object contains valid codec configuration. * * @return true if the object contains valid codec configuration, otherwise false. + * @hide */ public boolean isValid() { return (mSampleRate != SAMPLE_RATE_NONE) @@ -242,6 +306,12 @@ public final class BluetoothCodecConfig implements Parcelable { + ",mCodecSpecific4:" + mCodecSpecific4 + "}"; } + /** + * Always returns 0 + * + * @return 0 + * @hide + */ @Override public int describeContents() { return 0; @@ -271,6 +341,14 @@ public final class BluetoothCodecConfig implements Parcelable { } }; + /** + * Flattens the object to a parcel + * + * @param out The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. + * + * @hide + */ @Override public void writeToParcel(Parcel out, int flags) { out.writeInt(mCodecType); @@ -289,7 +367,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @return the codec name */ - public String getCodecName() { + public @NonNull String getCodecName() { switch (mCodecType) { case SOURCE_CODEC_TYPE_SBC: return "SBC"; @@ -315,8 +393,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @return the codec type */ - @UnsupportedAppUsage - public int getCodecType() { + public @SourceCodecType int getCodecType() { return mCodecType; } @@ -336,8 +413,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @return the codec priority */ - @UnsupportedAppUsage - public int getCodecPriority() { + public @CodecPriority int getCodecPriority() { return mCodecPriority; } @@ -347,9 +423,10 @@ public final class BluetoothCodecConfig implements Parcelable { * means higher priority. If 0, reset to default. * * @param codecPriority the codec priority + * @hide */ @UnsupportedAppUsage - public void setCodecPriority(int codecPriority) { + public void setCodecPriority(@CodecPriority int codecPriority) { mCodecPriority = codecPriority; } @@ -366,8 +443,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @return the codec sample rate */ - @UnsupportedAppUsage - public int getSampleRate() { + public @SampleRate int getSampleRate() { return mSampleRate; } @@ -381,8 +457,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @return the codec bits per sample */ - @UnsupportedAppUsage - public int getBitsPerSample() { + public @BitsPerSample int getBitsPerSample() { return mBitsPerSample; } @@ -394,9 +469,10 @@ public final class BluetoothCodecConfig implements Parcelable { * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_STEREO} * * @return the codec channel mode + * @hide */ @UnsupportedAppUsage - public int getChannelMode() { + public @ChannelMode int getChannelMode() { return mChannelMode; } @@ -405,7 +481,6 @@ public final class BluetoothCodecConfig implements Parcelable { * * @return a codec specific value1. */ - @UnsupportedAppUsage public long getCodecSpecific1() { return mCodecSpecific1; } @@ -414,6 +489,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Gets a codec specific value2. * * @return a codec specific value2 + * @hide */ @UnsupportedAppUsage public long getCodecSpecific2() { @@ -424,6 +500,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Gets a codec specific value3. * * @return a codec specific value3 + * @hide */ @UnsupportedAppUsage public long getCodecSpecific3() { @@ -434,6 +511,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Gets a codec specific value4. * * @return a codec specific value4 + * @hide */ @UnsupportedAppUsage public long getCodecSpecific4() { @@ -445,6 +523,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @param valueSet the value set presented by a bitmask * @return true if the valueSet contains zero or single bit, otherwise false. + * @hide */ private static boolean hasSingleBit(int valueSet) { return (valueSet == 0 || (valueSet & (valueSet - 1)) == 0); @@ -454,6 +533,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Checks whether the object contains none or single sample rate. * * @return true if the object contains none or single sample rate, otherwise false. + * @hide */ public boolean hasSingleSampleRate() { return hasSingleBit(mSampleRate); @@ -463,6 +543,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Checks whether the object contains none or single bits per sample. * * @return true if the object contains none or single bits per sample, otherwise false. + * @hide */ public boolean hasSingleBitsPerSample() { return hasSingleBit(mBitsPerSample); @@ -472,6 +553,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Checks whether the object contains none or single channel mode. * * @return true if the object contains none or single channel mode, otherwise false. + * @hide */ public boolean hasSingleChannelMode() { return hasSingleBit(mChannelMode); @@ -482,6 +564,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @param other the codec config to compare against * @return true if the audio feeding parameters are same, otherwise false + * @hide */ public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) { return (other != null && other.mSampleRate == mSampleRate @@ -495,6 +578,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @param other the codec config to compare against * @return true if the audio feeding parameters are similar, otherwise false. + * @hide */ public boolean similarCodecFeedingParameters(BluetoothCodecConfig other) { if (other == null || mCodecType != other.mCodecType) { @@ -526,6 +610,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @param other the codec config to compare against * @return true if the codec specific parameters are the same, otherwise false. + * @hide */ public boolean sameCodecSpecificParameters(BluetoothCodecConfig other) { if (other == null && mCodecType != other.mCodecType) { diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java index 58a764a85bed..b6e77391da5d 100644 --- a/core/java/android/bluetooth/BluetoothCodecStatus.java +++ b/core/java/android/bluetooth/BluetoothCodecStatus.java @@ -17,7 +17,7 @@ package android.bluetooth; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -32,6 +32,7 @@ import java.util.Objects; * * {@hide} */ +@SystemApi public final class BluetoothCodecStatus implements Parcelable { /** * Extra for the codec configuration intents of the individual profiles. @@ -39,17 +40,16 @@ public final class BluetoothCodecStatus implements Parcelable { * This extra represents the current codec status of the A2DP * profile. */ - @UnsupportedAppUsage public static final String EXTRA_CODEC_STATUS = - "android.bluetooth.codec.extra.CODEC_STATUS"; + "android.bluetooth.extra.CODEC_STATUS"; private final @Nullable BluetoothCodecConfig mCodecConfig; private final BluetoothCodecConfig[] mCodecsLocalCapabilities; private final BluetoothCodecConfig[] mCodecsSelectableCapabilities; - public BluetoothCodecStatus(BluetoothCodecConfig codecConfig, - BluetoothCodecConfig[] codecsLocalCapabilities, - BluetoothCodecConfig[] codecsSelectableCapabilities) { + public BluetoothCodecStatus(@Nullable BluetoothCodecConfig codecConfig, + @Nullable BluetoothCodecConfig[] codecsLocalCapabilities, + @Nullable BluetoothCodecConfig[] codecsSelectableCapabilities) { mCodecConfig = codecConfig; mCodecsLocalCapabilities = codecsLocalCapabilities; mCodecsSelectableCapabilities = codecsSelectableCapabilities; @@ -74,6 +74,7 @@ public final class BluetoothCodecStatus implements Parcelable { * @param c1 the first array of capabilities to compare * @param c2 the second array of capabilities to compare * @return true if both arrays contain same capabilities + * @hide */ public static boolean sameCapabilities(BluetoothCodecConfig[] c1, BluetoothCodecConfig[] c2) { @@ -95,6 +96,7 @@ public final class BluetoothCodecStatus implements Parcelable { * * @param codecConfig the codec config to compare against * @return true if the codec config matches, otherwise false + * @hide */ public boolean isCodecConfigSelectable(BluetoothCodecConfig codecConfig) { if (codecConfig == null || !codecConfig.hasSingleSampleRate() @@ -125,7 +127,12 @@ public final class BluetoothCodecStatus implements Parcelable { return false; } - + /** + * Returns a hash based on the codec config and local capabilities + * + * @return a hash based on the config values + * @hide + */ @Override public int hashCode() { return Objects.hash(mCodecConfig, mCodecsLocalCapabilities, @@ -140,6 +147,12 @@ public final class BluetoothCodecStatus implements Parcelable { + "}"; } + /** + * Always returns 0 + * + * @return 0 + * @hide + */ @Override public int describeContents() { return 0; @@ -165,6 +178,14 @@ public final class BluetoothCodecStatus implements Parcelable { } }; + /** + * Flattens the object to a parcel + * + * @param out The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. + * + * @hide + */ @Override public void writeToParcel(Parcel out, int flags) { out.writeTypedObject(mCodecConfig, 0); @@ -177,7 +198,6 @@ public final class BluetoothCodecStatus implements Parcelable { * * @return the current codec configuration */ - @UnsupportedAppUsage public @Nullable BluetoothCodecConfig getCodecConfig() { return mCodecConfig; } @@ -187,8 +207,7 @@ public final class BluetoothCodecStatus implements Parcelable { * * @return an array with the codecs local capabilities */ - @UnsupportedAppUsage - public BluetoothCodecConfig[] getCodecsLocalCapabilities() { + public @Nullable BluetoothCodecConfig[] getCodecsLocalCapabilities() { return mCodecsLocalCapabilities; } @@ -197,8 +216,7 @@ public final class BluetoothCodecStatus implements Parcelable { * * @return an array with the codecs selectable capabilities */ - @UnsupportedAppUsage - public BluetoothCodecConfig[] getCodecsSelectableCapabilities() { + public @Nullable BluetoothCodecConfig[] getCodecsSelectableCapabilities() { return mCodecsSelectableCapabilities; } } diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 0be3eca8239e..49187dcde342 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1131,20 +1131,7 @@ public final class BluetoothDevice implements Parcelable { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean createBond() { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device"); - return false; - } - try { - Log.i(TAG, "createBond() for device " + getAddress() - + " called by pid: " + Process.myPid() - + " tid: " + Process.myTid()); - return service.createBond(this, TRANSPORT_AUTO); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; + return createBond(TRANSPORT_AUTO); } /** @@ -1165,23 +1152,7 @@ public final class BluetoothDevice implements Parcelable { */ @UnsupportedAppUsage public boolean createBond(int transport) { - final IBluetooth service = sService; - if (service == null) { - Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device"); - return false; - } - if (TRANSPORT_AUTO > transport || transport > TRANSPORT_LE) { - throw new IllegalArgumentException(transport + " is not a valid Bluetooth transport"); - } - try { - Log.i(TAG, "createBond() for device " + getAddress() - + " called by pid: " + Process.myPid() - + " tid: " + Process.myTid()); - return service.createBond(this, transport); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; + return createBondOutOfBand(transport, null); } /** @@ -1209,7 +1180,7 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.createBondOutOfBand(this, transport, oobData); + return service.createBond(this, transport, oobData); } catch (RemoteException e) { Log.e(TAG, "", e); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index d370a380bc3b..7b580c3bde79 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4973,7 +4973,7 @@ public abstract class Context { * {@link android.content.pm.DataLoaderManager}. * @hide */ - public static final String DATA_LOADER_MANAGER_SERVICE = "dataloadermanager"; + public static final String DATA_LOADER_MANAGER_SERVICE = "dataloader_manager"; /** * Use with {@link #getSystemService(String)} to retrieve an diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 7815a330217f..ca2de6a8d1e4 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4000,9 +4000,15 @@ public class Intent implements Parcelable, Cloneable { * Broadcast Action: The sim card state has changed. * For more details see TelephonyIntents.ACTION_SIM_STATE_CHANGED. This is here * because TelephonyIntents is an internal class. - * @hide + * The intent will have following extras.</p> + * <p> + * @see #EXTRA_SIM_STATE + * @see #EXTRA_SIM_LOCKED_REASON + * * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} or * {@link #ACTION_SIM_APPLICATION_STATE_CHANGED} + * + * @hide */ @Deprecated @SystemApi @@ -4010,6 +4016,170 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED"; /** + * The extra used with {@link #ACTION_SIM_STATE_CHANGED} for broadcasting SIM STATE. + * This will have one of the following intent values. + * @see #SIM_STATE_UNKNOWN + * @see #SIM_STATE_NOT_READY + * @see #SIM_STATE_ABSENT + * @see #SIM_STATE_PRESENT + * @see #SIM_STATE_CARD_IO_ERROR + * @see #SIM_STATE_CARD_RESTRICTED + * @see #SIM_STATE_LOCKED + * @see #SIM_STATE_READY + * @see #SIM_STATE_IMSI + * @see #SIM_STATE_LOADED + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String EXTRA_SIM_STATE = "ss"; + + /** + * The intent value UNKNOWN represents the SIM state unknown + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String SIM_STATE_UNKNOWN = "UNKNOWN"; + + /** + * The intent value NOT_READY means that the SIM is not ready eg. radio is off or powering on + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String SIM_STATE_NOT_READY = "NOT_READY"; + + /** + * The intent value ABSENT means the SIM card is missing + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String SIM_STATE_ABSENT = "ABSENT"; + + /** + * The intent value PRESENT means the device has a SIM card inserted + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String SIM_STATE_PRESENT = "PRESENT"; + + /** + * The intent value CARD_IO_ERROR means for three consecutive times there was SIM IO error + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} + */ + @Deprecated + @SystemApi + static public final String SIM_STATE_CARD_IO_ERROR = "CARD_IO_ERROR"; + + /** + * The intent value CARD_RESTRICTED means card is present but not usable due to carrier + * restrictions + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} + */ + @Deprecated + @SystemApi + static public final String SIM_STATE_CARD_RESTRICTED = "CARD_RESTRICTED"; + + /** + * The intent value LOCKED means the SIM is locked by PIN or by network + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String SIM_STATE_LOCKED = "LOCKED"; + + /** + * The intent value READY means the SIM is ready to be accessed + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String SIM_STATE_READY = "READY"; + + /** + * The intent value IMSI means the SIM IMSI is ready in property + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String SIM_STATE_IMSI = "IMSI"; + + /** + * The intent value LOADED means all SIM records, including IMSI, are loaded + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String SIM_STATE_LOADED = "LOADED"; + + /** + * The extra used with {@link #ACTION_SIM_STATE_CHANGED} for broadcasting SIM STATE. + * This extra will have one of the following intent values. + * <p> + * @see #SIM_LOCKED_ON_PIN + * @see #SIM_LOCKED_ON_PUK + * @see #SIM_LOCKED_NETWORK + * @see #SIM_ABSENT_ON_PERM_DISABLED + * + * @hide + * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String EXTRA_SIM_LOCKED_REASON = "reason"; + + /** + * The intent value PIN means the SIM is locked on PIN1 + * @hide + * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String SIM_LOCKED_ON_PIN = "PIN"; + + /** + * The intent value PUK means the SIM is locked on PUK1 + * @hide + * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED} + */ + /* PUK means ICC is locked on PUK1 */ + @Deprecated + @SystemApi + public static final String SIM_LOCKED_ON_PUK = "PUK"; + + /** + * The intent value NETWORK means the SIM is locked on NETWORK PERSONALIZATION + * @hide + * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String SIM_LOCKED_NETWORK = "NETWORK"; + + /** + * The intent value PERM_DISABLED means SIM is permanently disabled due to puk fails + * @hide + * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String SIM_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED"; + + /** * Broadcast Action: indicate that the phone service state has changed. * The intent will have the following extra values:</p> * <p> diff --git a/core/java/android/content/integrity/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java index c8e164f1f232..574a93ff9355 100644 --- a/core/java/android/content/integrity/AtomicFormula.java +++ b/core/java/android/content/integrity/AtomicFormula.java @@ -44,6 +44,7 @@ public abstract class AtomicFormula implements Formula { private static final String TAG = "AtomicFormula"; + /** @hide */ @IntDef( value = { PACKAGE_NAME, @@ -56,6 +57,7 @@ public abstract class AtomicFormula implements Formula { @Retention(RetentionPolicy.SOURCE) public @interface Key {} + /** @hide */ @IntDef(value = {EQ, LT, LE, GT, GE}) @Retention(RetentionPolicy.SOURCE) public @interface Operator {} diff --git a/core/java/android/content/integrity/CompoundFormula.java b/core/java/android/content/integrity/CompoundFormula.java index 53a99534906c..2a651d9e90d8 100644 --- a/core/java/android/content/integrity/CompoundFormula.java +++ b/core/java/android/content/integrity/CompoundFormula.java @@ -47,6 +47,7 @@ import java.util.Objects; public final class CompoundFormula implements Formula, Parcelable { private static final String TAG = "OpenFormula"; + /** @hide */ @IntDef( value = { AND, OR, NOT, diff --git a/core/java/android/content/integrity/Formula.java b/core/java/android/content/integrity/Formula.java index 030ff6b66e1f..b092a22c0191 100644 --- a/core/java/android/content/integrity/Formula.java +++ b/core/java/android/content/integrity/Formula.java @@ -38,6 +38,7 @@ import java.lang.annotation.RetentionPolicy; @SystemApi @VisibleForTesting public interface Formula { + /** @hide */ @IntDef( value = { COMPOUND_FORMULA_TAG, diff --git a/core/java/android/content/integrity/Rule.java b/core/java/android/content/integrity/Rule.java index 914f1479edf3..39a0909321d0 100644 --- a/core/java/android/content/integrity/Rule.java +++ b/core/java/android/content/integrity/Rule.java @@ -42,6 +42,7 @@ import java.util.Objects; @VisibleForTesting public final class Rule implements Parcelable { + /** @hide */ @IntDef( value = { DENY, diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index e72444399dd0..26193f6ebb3d 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1376,7 +1376,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { this.minHeight = minHeight; } - WindowLayout(Parcel source) { + /** @hide */ + public WindowLayout(Parcel source) { width = source.readInt(); widthFraction = source.readFloat(); height = source.readInt(); diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index d6fb28f694fd..aa0002df2c3a 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -373,8 +373,9 @@ public class PackageInfo implements Parcelable { /** * Whether the overlay is static, meaning it cannot be enabled/disabled at runtime. + * @hide */ - boolean mOverlayIsStatic; + public boolean mOverlayIsStatic; /** * The user-visible SDK version (ex. 26) of the framework against which the application claims diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index e9fc8f6acfc6..f017aad25c0c 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -185,7 +185,8 @@ public class PackageInstaller { * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED}, * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT}, * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, - * {@link #STATUS_FAILURE_STORAGE}. + * {@link #STATUS_FAILURE_STORAGE}, {@link #STATUS_FAILURE_NAME_NOT_FOUND}, + * {@link #STATUS_FAILURE_ILLEGAL_STATE} or {@link #STATUS_FAILURE_SECURITY}. * <p> * More information about a status may be available through additional * extras; see the individual status documentation for details. @@ -1130,9 +1131,14 @@ public class PackageInstaller { * * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES * permission. - * @param statusReceiver Called when the state of the session changes. Intents sent to this - * receiver contain {@link #EXTRA_STATUS}. Refer to the individual - * transfer status codes on how to handle them. + * @param statusReceiver Called when the state of the session changes. Intents sent to + * this receiver contain {@link #EXTRA_STATUS}. Possible statuses: + * {@link #STATUS_FAILURE_NAME_NOT_FOUND}, + * {@link #STATUS_FAILURE_ILLEGAL_STATE}, + * {@link #STATUS_FAILURE_SECURITY}, + * {@link #STATUS_FAILURE}. + * Refer to the individual transfer status codes on how to handle + * them. * * @throws PackageManager.NameNotFoundException if the new owner could not be found. * @throws SecurityException if called after the session has been committed or abandoned. diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index cf21e9665c71..65ee1e5f0370 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -57,6 +57,12 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageParserCacheHelper.ReadHelper; import android.content.pm.PackageParserCacheHelper.WriteHelper; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ApkParseUtils; +import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.PackageInfoUtils; +import android.content.pm.parsing.ParsedPackage; import android.content.pm.permission.SplitPermissionInfoParcelable; import android.content.pm.split.DefaultSplitAssetLoader; import android.content.pm.split.SplitAssetDependencyLoader; @@ -67,7 +73,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; -import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.FileUtils; @@ -156,21 +161,22 @@ import java.util.concurrent.atomic.AtomicInteger; * @hide */ public class PackageParser { - private static final boolean DEBUG_JAR = false; - private static final boolean DEBUG_PARSER = false; - private static final boolean DEBUG_BACKUP = false; - private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE; - private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100; + + public static final boolean DEBUG_JAR = false; + public static final boolean DEBUG_PARSER = false; + public static final boolean DEBUG_BACKUP = false; + public static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE; + public static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100; private static final String PROPERTY_CHILD_PACKAGES_ENABLED = "persist.sys.child_packages_enabled"; - private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE && + public static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false); - private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f; - private static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO = 1.333f; - private static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH = 1f; + public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f; + public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO = 1.333f; + public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH = 1f; private static final int DEFAULT_MIN_SDK_VERSION = 1; private static final int DEFAULT_TARGET_SDK_VERSION = 0; @@ -182,37 +188,38 @@ public class PackageParser { public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"; /** Path prefix for apps on expanded storage */ - private static final String MNT_EXPAND = "/mnt/expand/"; - - private static final String TAG_MANIFEST = "manifest"; - private static final String TAG_APPLICATION = "application"; - private static final String TAG_PACKAGE_VERIFIER = "package-verifier"; - private static final String TAG_OVERLAY = "overlay"; - private static final String TAG_KEY_SETS = "key-sets"; - private static final String TAG_PERMISSION_GROUP = "permission-group"; - private static final String TAG_PERMISSION = "permission"; - private static final String TAG_PERMISSION_TREE = "permission-tree"; - private static final String TAG_USES_PERMISSION = "uses-permission"; - private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m"; - private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23"; - private static final String TAG_USES_CONFIGURATION = "uses-configuration"; - private static final String TAG_USES_FEATURE = "uses-feature"; - private static final String TAG_FEATURE_GROUP = "feature-group"; - private static final String TAG_USES_SDK = "uses-sdk"; - private static final String TAG_SUPPORT_SCREENS = "supports-screens"; - private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast"; - private static final String TAG_INSTRUMENTATION = "instrumentation"; - private static final String TAG_ORIGINAL_PACKAGE = "original-package"; - private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; - private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture"; - private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens"; - private static final String TAG_SUPPORTS_INPUT = "supports-input"; - private static final String TAG_EAT_COMMENT = "eat-comment"; - private static final String TAG_PACKAGE = "package"; - private static final String TAG_RESTRICT_UPDATE = "restrict-update"; - private static final String TAG_USES_SPLIT = "uses-split"; - - private static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect"; + public static final String MNT_EXPAND = "/mnt/expand/"; + + public static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; + public static final String TAG_APPLICATION = "application"; + public static final String TAG_COMPATIBLE_SCREENS = "compatible-screens"; + public static final String TAG_EAT_COMMENT = "eat-comment"; + public static final String TAG_FEATURE_GROUP = "feature-group"; + public static final String TAG_INSTRUMENTATION = "instrumentation"; + public static final String TAG_KEY_SETS = "key-sets"; + public static final String TAG_MANIFEST = "manifest"; + public static final String TAG_ORIGINAL_PACKAGE = "original-package"; + public static final String TAG_OVERLAY = "overlay"; + public static final String TAG_PACKAGE = "package"; + public static final String TAG_PACKAGE_VERIFIER = "package-verifier"; + public static final String TAG_PERMISSION = "permission"; + public static final String TAG_PERMISSION_GROUP = "permission-group"; + public static final String TAG_PERMISSION_TREE = "permission-tree"; + public static final String TAG_PROTECTED_BROADCAST = "protected-broadcast"; + public static final String TAG_QUERIES = "queries"; + public static final String TAG_RESTRICT_UPDATE = "restrict-update"; + public static final String TAG_SUPPORT_SCREENS = "supports-screens"; + public static final String TAG_SUPPORTS_INPUT = "supports-input"; + public static final String TAG_USES_CONFIGURATION = "uses-configuration"; + public static final String TAG_USES_FEATURE = "uses-feature"; + public static final String TAG_USES_GL_TEXTURE = "uses-gl-texture"; + public static final String TAG_USES_PERMISSION = "uses-permission"; + public static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23"; + public static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m"; + public static final String TAG_USES_SDK = "uses-sdk"; + public static final String TAG_USES_SPLIT = "uses-split"; + + public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect"; /** * Bit mask of all the valid bits that can be set in recreateOnConfigChanges. @@ -222,25 +229,25 @@ public class PackageParser { ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC; // These are the tags supported by child packages - private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>(); + public static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>(); static { CHILD_PACKAGE_TAGS.add(TAG_APPLICATION); - CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION); - CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M); - CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23); - CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION); - CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE); + CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS); + CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT); CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP); - CHILD_PACKAGE_TAGS.add(TAG_USES_SDK); - CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS); CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION); - CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE); - CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS); + CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS); CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT); - CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT); + CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION); + CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE); + CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE); + CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION); + CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23); + CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M); + CHILD_PACKAGE_TAGS.add(TAG_USES_SDK); } - private static final boolean LOG_UNSAFE_BROADCASTS = false; + public static final boolean LOG_UNSAFE_BROADCASTS = false; /** * Total number of packages that were read from the cache. We use it only for logging. @@ -248,7 +255,7 @@ public class PackageParser { public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger(); // Set of broadcast actions that are safe for manifest receivers - private static final Set<String> SAFE_BROADCASTS = new ArraySet<>(); + public static final Set<String> SAFE_BROADCASTS = new ArraySet<>(); static { SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED); } @@ -295,26 +302,29 @@ public class PackageParser { * @deprecated callers should move to explicitly passing around source path. */ @Deprecated - private String mArchiveSourcePath; + public String mArchiveSourcePath; - private String[] mSeparateProcesses; + public String[] mSeparateProcesses; private boolean mOnlyCoreApps; private DisplayMetrics mMetrics; @UnsupportedAppUsage - private Callback mCallback; + public Callback mCallback; private File mCacheDir; - private static final int SDK_VERSION = Build.VERSION.SDK_INT; - private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES; + public static final int SDK_VERSION = Build.VERSION.SDK_INT; + public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES; + + public int mParseError = PackageManager.INSTALL_SUCCEEDED; - private int mParseError = PackageManager.INSTALL_SUCCEEDED; + public ThreadLocal<ApkParseUtils.ParseResult> mSharedResult + = ThreadLocal.withInitial(ApkParseUtils.ParseResult::new); - private static boolean sCompatibilityModeEnabled = true; - private static boolean sUseRoundIcon = false; + public static boolean sCompatibilityModeEnabled = true; + public static boolean sUseRoundIcon = false; - private static final int PARSE_DEFAULT_INSTALL_LOCATION = + public static final int PARSE_DEFAULT_INSTALL_LOCATION = PackageInfo.INSTALL_LOCATION_UNSPECIFIED; - private static final int PARSE_DEFAULT_TARGET_SANDBOX = 1; + public static final int PARSE_DEFAULT_TARGET_SANDBOX = 1; static class ParsePackageItemArgs { final Package owner; @@ -536,7 +546,7 @@ public class PackageParser { * the DTD. Otherwise, we try to get as much from the package as we * can without failing. This should normally be set to false, to * support extensions to the DTD in future versions. */ - private static final boolean RIGID_PARSER = false; + public static final boolean RIGID_PARSER = false; private static final String TAG = "PackageParser"; @@ -887,7 +897,7 @@ public class PackageParser { @Retention(RetentionPolicy.SOURCE) public @interface ParseFlags {} - private static final Comparator<String> sSplitNameComparator = new SplitNameComparator(); + public static final Comparator<String> sSplitNameComparator = new SplitNameComparator(); /** * Used to sort a set of APKs based on their split names, always placing the @@ -1033,7 +1043,7 @@ public class PackageParser { * and unique split names. * <p> * Note that this <em>does not</em> perform signature verification; that - * must be done separately in {@link #collectCertificates(Package, int)}. + * must be done separately in {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}. * * If {@code useCaches} is true, the package parser might return a cached * result from a previous parse of the same {@code packageFile} with the same @@ -1041,21 +1051,54 @@ public class PackageParser { * has changed since the last parse, it's up to callers to do so. * * @see #parsePackageLite(File, int) + * @deprecated use {@link #parseParsedPackage(File, int, boolean)} */ @UnsupportedAppUsage + @Deprecated public Package parsePackage(File packageFile, int flags, boolean useCaches) throws PackageParserException { - Package parsed = useCaches ? getCachedResult(packageFile, flags) : null; + if (packageFile.isDirectory()) { + return parseClusterPackage(packageFile, flags); + } else { + return parseMonolithicPackage(packageFile, flags); + } + } + + /** + * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}. + * @deprecated use {@link #parseParsedPackage(File, int, boolean)} + */ + @UnsupportedAppUsage + @Deprecated + public Package parsePackage(File packageFile, int flags) throws PackageParserException { + return parsePackage(packageFile, flags, false /* useCaches */); + } + + /** + * Updated method which returns {@link ParsedPackage}, the current representation of a + * package parsed from disk. + * + * @see #parsePackage(File, int, boolean) + */ + public ParsedPackage parseParsedPackage(File packageFile, int flags, boolean useCaches) + throws PackageParserException { + ParsedPackage parsed = useCaches ? getCachedResult(packageFile, flags) : null; if (parsed != null) { return parsed; } long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0; - if (packageFile.isDirectory()) { - parsed = parseClusterPackage(packageFile, flags); - } else { - parsed = parseMonolithicPackage(packageFile, flags); - } + ApkParseUtils.ParseInput parseInput = mSharedResult.get().reset(); + parsed = ApkParseUtils.parsePackage( + parseInput, + mSeparateProcesses, + mCallback, + mMetrics, + mOnlyCoreApps, + packageFile, + flags + ) + .hideAsParsed(); long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0; cacheResult(packageFile, flags, parsed); @@ -1067,19 +1110,12 @@ public class PackageParser { + "ms, update_cache=" + cacheTime + " ms"); } } - return parsed; - } - /** - * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}. - */ - @UnsupportedAppUsage - public Package parsePackage(File packageFile, int flags) throws PackageParserException { - return parsePackage(packageFile, flags, false /* useCaches */); + return parsed; } /** - * Returns the cache key for a specificied {@code packageFile} and {@code flags}. + * Returns the cache key for a specified {@code packageFile} and {@code flags}. */ private String getCacheKey(File packageFile, int flags) { StringBuilder sb = new StringBuilder(packageFile.getName()); @@ -1090,13 +1126,13 @@ public class PackageParser { } @VisibleForTesting - protected Package fromCacheEntry(byte[] bytes) { + protected ParsedPackage fromCacheEntry(byte[] bytes) { return fromCacheEntryStatic(bytes); } /** static version of {@link #fromCacheEntry} for unit tests. */ @VisibleForTesting - public static Package fromCacheEntryStatic(byte[] bytes) { + public static ParsedPackage fromCacheEntryStatic(byte[] bytes) { final Parcel p = Parcel.obtain(); p.unmarshall(bytes, 0, bytes.length); p.setDataPosition(0); @@ -1104,7 +1140,8 @@ public class PackageParser { final ReadHelper helper = new ReadHelper(p); helper.startAndInstall(); - PackageParser.Package pkg = new PackageParser.Package(p); + // TODO(b/135203078): Hide PackageImpl constructor? + ParsedPackage pkg = new PackageImpl(p); p.recycle(); @@ -1114,14 +1151,14 @@ public class PackageParser { } @VisibleForTesting - protected byte[] toCacheEntry(Package pkg) { + protected byte[] toCacheEntry(ParsedPackage pkg) { return toCacheEntryStatic(pkg); } /** static version of {@link #toCacheEntry} for unit tests. */ @VisibleForTesting - public static byte[] toCacheEntryStatic(Package pkg) { + public static byte[] toCacheEntryStatic(ParsedPackage pkg) { final Parcel p = Parcel.obtain(); final WriteHelper helper = new WriteHelper(p); @@ -1170,7 +1207,7 @@ public class PackageParser { * Returns the cached parse result for {@code packageFile} for parse flags {@code flags}, * or {@code null} if no cached result exists. */ - private Package getCachedResult(File packageFile, int flags) { + public ParsedPackage getCachedResult(File packageFile, int flags) { if (mCacheDir == null) { return null; } @@ -1199,7 +1236,7 @@ public class PackageParser { /** * Caches the parse result for {@code packageFile} with flags {@code flags}. */ - private void cacheResult(File packageFile, int flags, Package parsed) { + public void cacheResult(File packageFile, int flags, ParsedPackage parsed) { if (mCacheDir == null) { return; } @@ -1238,7 +1275,8 @@ public class PackageParser { * split names. * <p> * Note that this <em>does not</em> perform signature verification; that - * must be done separately in {@link #collectCertificates(Package, int)}. + * must be done separately in + * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}. */ private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException { final PackageLite lite = parseClusterPackageLite(packageDir, 0); @@ -1302,10 +1340,11 @@ public class PackageParser { * Parse the given APK file, treating it as as a single monolithic package. * <p> * Note that this <em>does not</em> perform signature verification; that - * must be done separately in {@link #collectCertificates(Package, int)}. + * must be done separately in + * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}. * * @deprecated external callers should move to - * {@link #parsePackage(File, int)}. Eventually this method will + * {@link #parseParsedPackage(File, int, boolean)}. Eventually this method will * be marked private. */ @Deprecated @@ -1505,8 +1544,11 @@ public class PackageParser { * Collect certificates from all the APKs described in the given package, * populating {@link Package#mSigningDetails}. Also asserts that all APK * contents are signed correctly and consistently. + * + * @deprecated use {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)} */ @UnsupportedAppUsage + @Deprecated public static void collectCertificates(Package pkg, boolean skipVerify) throws PackageParserException { collectCertificatesInternal(pkg, skipVerify); @@ -1685,7 +1727,7 @@ public class PackageParser { ? null : "must have at least one '.' separator"; } - private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser, + public static Pair<String, String> parsePackageSplitNames(XmlPullParser parser, AttributeSet attrs) throws IOException, XmlPullParserException, PackageParserException { @@ -2454,8 +2496,6 @@ public class PackageParser { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; - } else if (tagName.equals("queries")) { - parseQueries(pkg, res, parser, flags, outError); } else { Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() + " at " + mArchiveSourcePath + " " @@ -2925,7 +2965,7 @@ public class PackageParser { return true; } - private static String buildClassName(String pkg, CharSequence clsSeq, + public static String buildClassName(String pkg, CharSequence clsSeq, String[] outError) { if (clsSeq == null || clsSeq.length() <= 0) { outError[0] = "Empty class name in package " + pkg; @@ -2973,7 +3013,7 @@ public class PackageParser { return proc; } - private static String buildProcessName(String pkg, String defProc, + public static String buildProcessName(String pkg, String defProc, CharSequence procSeq, int flags, String[] separateProcesses, String[] outError) { if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) { @@ -2993,7 +3033,7 @@ public class PackageParser { return TextUtils.safeIntern(buildCompoundName(pkg, procSeq, "process", outError)); } - private static String buildTaskAffinityName(String pkg, String defProc, + public static String buildTaskAffinityName(String pkg, String defProc, CharSequence procSeq, String[] outError) { if (procSeq == null) { return defProc; @@ -3555,9 +3595,6 @@ public class PackageParser { owner.mRequiredAccountType = requiredAccountType; } - owner.mForceQueryable = - sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false); - if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_debuggable, false)) { @@ -4019,89 +4056,6 @@ public class PackageParser { return true; } - private boolean parseQueries(Package owner, Resources res, XmlResourceParser parser, int flags, - String[] outError) - throws IOException, XmlPullParserException { - - final int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - if (parser.getName().equals("intent")) { - QueriesIntentInfo intentInfo = new QueriesIntentInfo(); - if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/, - intentInfo, outError)) { - return false; - } - - Uri data = null; - String dataType = null; - String host = ""; - final int numActions = intentInfo.countActions(); - final int numSchemes = intentInfo.countDataSchemes(); - final int numTypes = intentInfo.countDataTypes(); - final int numHosts = intentInfo.getHosts().length; - if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) { - outError[0] = "intent tags must contain either an action or data."; - return false; - } - if (numActions > 1) { - outError[0] = "intent tag may have at most one action."; - return false; - } - if (numTypes > 1) { - outError[0] = "intent tag may have at most one data type."; - return false; - } - if (numSchemes > 1) { - outError[0] = "intent tag may have at most one data scheme."; - return false; - } - if (numHosts > 1) { - outError[0] = "intent tag may have at most one data host."; - return false; - } - Intent intent = new Intent(); - for (int i = 0, max = intentInfo.countCategories(); i < max; i++) { - intent.addCategory(intentInfo.getCategory(i)); - } - if (numHosts == 1) { - host = intentInfo.getHosts()[0]; - } - if (numSchemes == 1) { - data = new Uri.Builder() - .scheme(intentInfo.getDataScheme(0)) - .authority(host) - .build(); - } - if (numTypes == 1) { - dataType = intentInfo.getDataType(0); - } - intent.setDataAndType(data, dataType); - if (numActions == 1) { - intent.setAction(intentInfo.getAction(0)); - } - owner.mQueriesIntents = ArrayUtils.add(owner.mQueriesIntents, intent); - } else if (parser.getName().equals("package")) { - final TypedArray sa = res.obtainAttributes(parser, - com.android.internal.R.styleable.AndroidManifestQueriesPackage); - final String packageName = - sa.getString(R.styleable.AndroidManifestQueriesPackage_name); - if (TextUtils.isEmpty(packageName)) { - outError[0] = "Package name is missing from package tag."; - return false; - } - owner.mQueriesPackages = - ArrayUtils.add(owner.mQueriesPackages, packageName.intern()); - } - } - return true; - } - /** * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI */ @@ -5813,7 +5767,7 @@ public class PackageParser { return null; } - private static final String ANDROID_RESOURCES + public static final String ANDROID_RESOURCES = "http://schemas.android.com/apk/res/android"; private boolean parseIntent(Resources res, XmlResourceParser parser, boolean allowGlobs, @@ -6508,7 +6462,10 @@ public class PackageParser { /** * Representation of a full package parsed from APK files on disk. A package * consists of a single base APK, and zero or more split APKs. + * + * @deprecated use an {@link AndroidPackage} */ + @Deprecated public final static class Package implements Parcelable { @UnsupportedAppUsage @@ -6616,9 +6573,6 @@ public class PackageParser { // The major version code declared for this package. public int mVersionCodeMajor; - // Whether the package declares that it should be queryable by all normal apps on device. - public boolean mForceQueryable; - // Return long containing mVersionCode and mVersionCodeMajor. public long getLongVersionCode() { return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode); @@ -6724,9 +6678,6 @@ public class PackageParser { /** Whether or not the package is a stub and must be replaced by the full version. */ public boolean isStub; - public ArrayList<String> mQueriesPackages; - public ArrayList<Intent> mQueriesIntents; - @UnsupportedAppUsage public Package(String packageName) { this.packageName = packageName; @@ -7230,9 +7181,6 @@ public class PackageParser { use32bitAbi = (dest.readInt() == 1); restrictUpdateHash = dest.createByteArray(); visibleToInstantApps = dest.readInt() == 1; - mForceQueryable = dest.readBoolean(); - mQueriesIntents = dest.createTypedArrayList(Intent.CREATOR); - mQueriesPackages = dest.createStringArrayList(); } private static void internStringArrayList(List<String> list) { @@ -7248,7 +7196,7 @@ public class PackageParser { * Sets the package owner and the the {@code applicationInfo} for every component * owner by this package. */ - private void fixupOwner(List<? extends Component<?>> list) { + public void fixupOwner(List<? extends Component<?>> list) { if (list != null) { for (Component<?> c : list) { c.owner = this; @@ -7358,12 +7306,8 @@ public class PackageParser { dest.writeInt(use32bitAbi ? 1 : 0); dest.writeByteArray(restrictUpdateHash); dest.writeInt(visibleToInstantApps ? 1 : 0); - dest.writeBoolean(mForceQueryable); - dest.writeTypedList(mQueriesIntents); - dest.writeList(mQueriesPackages); } - /** * Writes the keyset mapping to the provided package. {@code null} mappings are permitted. */ @@ -7435,6 +7379,10 @@ public class PackageParser { }; } + /** + * @deprecated use a {@link ComponentParseUtils.ParsedComponent} + */ + @Deprecated public static abstract class Component<II extends IntentInfo> { @UnsupportedAppUsage public final ArrayList<II> intents; @@ -7615,6 +7563,10 @@ public class PackageParser { } } + /** + * @deprecated use {@link ComponentParseUtils.ParsedPermission} + */ + @Deprecated public final static class Permission extends Component<IntentInfo> implements Parcelable { @UnsupportedAppUsage public final PermissionInfo info; @@ -7689,6 +7641,10 @@ public class PackageParser { }; } + /** + * @deprecated use {@link ComponentParseUtils.ParsedPermissionGroup} + */ + @Deprecated public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable { @UnsupportedAppUsage public final PermissionGroupInfo info; @@ -7788,7 +7744,12 @@ public class PackageParser { return false; } + /** + * @deprecated use {@link PackageInfoUtils#generateApplicationInfo( + * AndroidPackage, int, PackageUserState, int)} + */ @UnsupportedAppUsage + @Deprecated public static ApplicationInfo generateApplicationInfo(Package p, int flags, PackageUserState state) { return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId()); @@ -7845,7 +7806,12 @@ public class PackageParser { ai.icon = (sUseRoundIcon && ai.roundIconRes != 0) ? ai.roundIconRes : ai.iconRes; } + /** + * @deprecated use {@link PackageInfoUtils#generateApplicationInfo( + * AndroidPackage, int, PackageUserState, int)} + */ @UnsupportedAppUsage + @Deprecated public static ApplicationInfo generateApplicationInfo(Package p, int flags, PackageUserState state, int userId) { if (p == null) return null; @@ -7885,6 +7851,11 @@ public class PackageParser { return ai; } + /** + * @deprecated use {@link PackageInfoUtils#generateApplicationInfo( + * AndroidPackage, int, PackageUserState, int)} + */ + @Deprecated public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags, PackageUserState state, int userId) { if (ai == null) return null; @@ -7904,7 +7875,12 @@ public class PackageParser { return ai; } + /** + * @deprecated use {@link PackageInfoUtils#generatePermissionInfo( + * ComponentParseUtils.ParsedPermission, int)} + */ @UnsupportedAppUsage + @Deprecated public static final PermissionInfo generatePermissionInfo( Permission p, int flags) { if (p == null) return null; @@ -7916,7 +7892,12 @@ public class PackageParser { return pi; } + /** + * @deprecated use {@link PackageInfoUtils#generatePermissionGroupInfo( + * ComponentParseUtils.ParsedPermissionGroup, int)} + */ @UnsupportedAppUsage + @Deprecated public static final PermissionGroupInfo generatePermissionGroupInfo( PermissionGroup pg, int flags) { if (pg == null) return null; @@ -7928,6 +7909,10 @@ public class PackageParser { return pgi; } + /** + * @deprecated use {@link ComponentParseUtils.ParsedActivity} + */ + @Deprecated public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable { @UnsupportedAppUsage public final ActivityInfo info; @@ -8043,7 +8028,12 @@ public class PackageParser { }; } + /** + * @deprecated use {@link PackageInfoUtils#generateActivityInfo( + * AndroidPackage, ComponentParseUtils.ParsedActivity, int, PackageUserState, int)} + */ @UnsupportedAppUsage + @Deprecated public static final ActivityInfo generateActivityInfo(Activity a, int flags, PackageUserState state, int userId) { if (a == null) return null; @@ -8061,6 +8051,11 @@ public class PackageParser { return ai; } + /** + * @deprecated use {@link PackageInfoUtils#generateActivityInfo( + * AndroidPackage, ComponentParseUtils.ParsedActivity, int, PackageUserState, int)} + */ + @Deprecated public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags, PackageUserState state, int userId) { if (ai == null) return null; @@ -8074,6 +8069,10 @@ public class PackageParser { return ai; } + /** + * @deprecated use {@link ComponentParseUtils.ParsedService} + */ + @Deprecated public final static class Service extends Component<ServiceIntentInfo> implements Parcelable { @UnsupportedAppUsage public final ServiceInfo info; @@ -8135,7 +8134,12 @@ public class PackageParser { }; } + /** + * @deprecated use {@link PackageInfoUtils#generateServiceInfo( + * AndroidPackage, ComponentParseUtils.ParsedService, int, PackageUserState, int)} + */ @UnsupportedAppUsage + @Deprecated public static final ServiceInfo generateServiceInfo(Service s, int flags, PackageUserState state, int userId) { if (s == null) return null; @@ -8153,6 +8157,10 @@ public class PackageParser { return si; } + /** + * @deprecated use {@link ComponentParseUtils.ParsedProvider} + */ + @Deprecated public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable { @UnsupportedAppUsage public final ProviderInfo info; @@ -8233,7 +8241,12 @@ public class PackageParser { }; } + /** + * @deprecated use {@link PackageInfoUtils#generateProviderInfo( + * AndroidPackage, ComponentParseUtils.ParsedProvider, int, PackageUserState, int)} + */ @UnsupportedAppUsage + @Deprecated public static final ProviderInfo generateProviderInfo(Provider p, int flags, PackageUserState state, int userId) { if (p == null) return null; @@ -8256,6 +8269,10 @@ public class PackageParser { return pi; } + /** + * @deprecated use {@link ComponentParseUtils.ParsedInstrumentation} + */ + @Deprecated public final static class Instrumentation extends Component<IntentInfo> implements Parcelable { @UnsupportedAppUsage @@ -8316,7 +8333,12 @@ public class PackageParser { }; } + /** + * @deprecated use {@link PackageInfoUtils#generateInstrumentationInfo( + * ComponentParseUtils.ParsedInstrumentation, int)} + */ @UnsupportedAppUsage + @Deprecated public static final InstrumentationInfo generateInstrumentationInfo( Instrumentation i, int flags) { if (i == null) return null; @@ -8328,6 +8350,10 @@ public class PackageParser { return ii; } + /** + * @deprecated use {@link ComponentParseUtils.ParsedIntentInfo} + */ + @Deprecated public static abstract class IntentInfo extends IntentFilter { @UnsupportedAppUsage public boolean hasDefault; @@ -8371,8 +8397,10 @@ public class PackageParser { } } - public static final class QueriesIntentInfo extends IntentInfo {} - + /** + * @deprecated use {@link ComponentParseUtils.ParsedActivityIntentInfo} + */ + @Deprecated public final static class ActivityIntentInfo extends IntentInfo { @UnsupportedAppUsage public Activity activity; @@ -8396,6 +8424,10 @@ public class PackageParser { } } + /** + * @deprecated use {@link ComponentParseUtils.ParsedServiceIntentInfo} + */ + @Deprecated public final static class ServiceIntentInfo extends IntentInfo { @UnsupportedAppUsage public Service service; @@ -8419,6 +8451,10 @@ public class PackageParser { } } + /** + * @deprecated use {@link ComponentParseUtils.ParsedProviderIntentInfo} + */ + @Deprecated public static final class ProviderIntentInfo extends IntentInfo { @UnsupportedAppUsage public Provider provider; diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index 5c74efb8ff1b..55574c3cb880 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -28,6 +28,7 @@ import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPON import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import android.annotation.UnsupportedAppUsage; +import android.content.pm.parsing.ComponentParseUtils; import android.os.BaseBundle; import android.os.Debug; import android.os.PersistableBundle; @@ -127,6 +128,18 @@ public class PackageUserState { && (!this.hidden || matchUninstalled)); } + public boolean isMatch(ComponentInfo componentInfo, int flags) { + return isMatch(componentInfo.applicationInfo.isSystemApp(), + componentInfo.applicationInfo.enabled, componentInfo.enabled, + componentInfo.directBootAware, componentInfo.name, flags); + } + + public boolean isMatch(boolean isSystem, boolean isPackageEnabled, + ComponentParseUtils.ParsedComponent component, int flags) { + return isMatch(isSystem, isPackageEnabled, component.isEnabled(), + component.isDirectBootAware(), component.getName(), flags); + } + /** * Test if the given component is considered installed, enabled and a match * for the given flags. @@ -135,28 +148,33 @@ public class PackageUserState { * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and * {@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}. * </p> + * */ - public boolean isMatch(ComponentInfo componentInfo, int flags) { - final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp(); + public boolean isMatch(boolean isSystem, boolean isPackageEnabled, boolean isComponentEnabled, + boolean isComponentDirectBootAware, String componentName, int flags) { final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0; - if (!isAvailable(flags) - && !(isSystemApp && matchUninstalled)) return reportIfDebug(false, flags); - if (!isEnabled(componentInfo, flags)) return reportIfDebug(false, flags); + if (!isAvailable(flags) && !(isSystem && matchUninstalled)) { + return reportIfDebug(false, flags); + } + + if (!isEnabled(isPackageEnabled, isComponentEnabled, componentName, flags)) { + return reportIfDebug(false, flags); + } if ((flags & MATCH_SYSTEM_ONLY) != 0) { - if (!isSystemApp) { + if (!isSystem) { return reportIfDebug(false, flags); } } final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0) - && !componentInfo.directBootAware; + && !isComponentDirectBootAware; final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0) - && componentInfo.directBootAware; + && isComponentDirectBootAware; return reportIfDebug(matchesUnaware || matchesAware, flags); } - private boolean reportIfDebug(boolean result, int flags) { + public boolean reportIfDebug(boolean result, int flags) { if (DEBUG && !result) { Slog.i(LOG_TAG, "No match!; flags: " + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " " @@ -165,10 +183,22 @@ public class PackageUserState { return result; } + public boolean isEnabled(ComponentInfo componentInfo, int flags) { + return isEnabled(componentInfo.applicationInfo.enabled, componentInfo.enabled, + componentInfo.name, flags); + } + + public boolean isEnabled(boolean isPackageEnabled, + ComponentParseUtils.ParsedComponent parsedComponent, int flags) { + return isEnabled(isPackageEnabled, parsedComponent.isEnabled(), parsedComponent.getName(), + flags); + } + /** * Test if the given component is considered enabled. */ - public boolean isEnabled(ComponentInfo componentInfo, int flags) { + public boolean isEnabled(boolean isPackageEnabled, boolean isComponentEnabled, + String componentName, int flags) { if ((flags & MATCH_DISABLED_COMPONENTS) != 0) { return true; } @@ -183,24 +213,26 @@ public class PackageUserState { if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) { return false; } + // fallthrough case COMPONENT_ENABLED_STATE_DEFAULT: - if (!componentInfo.applicationInfo.enabled) { + if (!isPackageEnabled) { return false; } + // fallthrough case COMPONENT_ENABLED_STATE_ENABLED: break; } // Check if component has explicit state before falling through to // the manifest default - if (ArrayUtils.contains(this.enabledComponents, componentInfo.name)) { + if (ArrayUtils.contains(this.enabledComponents, componentName)) { return true; } - if (ArrayUtils.contains(this.disabledComponents, componentInfo.name)) { + if (ArrayUtils.contains(this.disabledComponents, componentName)) { return false; } - return componentInfo.enabled; + return isComponentEnabled; } @Override diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java index 3488cc30892c..2863b268e795 100644 --- a/core/java/android/content/pm/SharedLibraryInfo.java +++ b/core/java/android/content/pm/SharedLibraryInfo.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.pm.parsing.AndroidPackage; import android.os.Parcel; import android.os.Parcelable; @@ -38,20 +39,24 @@ import java.util.List; public final class SharedLibraryInfo implements Parcelable { /** @hide */ - public static SharedLibraryInfo createForStatic(PackageParser.Package pkg) { - return new SharedLibraryInfo(null, pkg.packageName, pkg.getAllCodePaths(), - pkg.staticSharedLibName, - pkg.staticSharedLibVersion, + public static SharedLibraryInfo createForStatic(AndroidPackage pkg) { + return new SharedLibraryInfo(null, pkg.getPackageName(), + pkg.makeListAllCodePaths(), + pkg.getStaticSharedLibName(), + pkg.getStaticSharedLibVersion(), TYPE_STATIC, - new VersionedPackage(pkg.manifestPackageName, pkg.getLongVersionCode()), + new VersionedPackage(pkg.getManifestPackageName(), + pkg.getLongVersionCode()), null, null); } /** @hide */ - public static SharedLibraryInfo createForDynamic(PackageParser.Package pkg, String name) { - return new SharedLibraryInfo(null, pkg.packageName, pkg.getAllCodePaths(), name, + public static SharedLibraryInfo createForDynamic(AndroidPackage pkg, String name) { + return new SharedLibraryInfo(null, pkg.getPackageName(), + pkg.makeListAllCodePaths(), name, (long) VERSION_UNDEFINED, - TYPE_DYNAMIC, new VersionedPackage(pkg.packageName, pkg.getLongVersionCode()), + TYPE_DYNAMIC, new VersionedPackage(pkg.getPackageName(), + pkg.getLongVersionCode()), null, null); } diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java index 5d10b8826b00..4cd201fbe538 100644 --- a/core/java/android/content/pm/dex/DexMetadataHelper.java +++ b/core/java/android/content/pm/dex/DexMetadataHelper.java @@ -22,6 +22,7 @@ import static android.content.pm.PackageParser.APK_FILE_EXTENSION; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.parsing.AndroidPackage; import android.util.ArrayMap; import android.util.jar.StrictJarFile; @@ -86,8 +87,8 @@ public class DexMetadataHelper { * * NOTE: involves I/O checks. */ - public static Map<String, String> getPackageDexMetadata(PackageParser.Package pkg) { - return buildPackageApkToDexMetadataMap(pkg.getAllCodePaths()); + public static Map<String, String> getPackageDexMetadata(AndroidPackage pkg) { + return buildPackageApkToDexMetadataMap(pkg.makeListAllCodePaths()); } /** @@ -160,7 +161,7 @@ public class DexMetadataHelper { * * @throws PackageParserException in case of errors. */ - public static void validatePackageDexMetadata(PackageParser.Package pkg) + public static void validatePackageDexMetadata(AndroidPackage pkg) throws PackageParserException { Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values(); for (String dexMetadata : apkToDexMetadataList) { diff --git a/core/java/android/content/pm/parsing/AndroidPackage.aidl b/core/java/android/content/pm/parsing/AndroidPackage.aidl new file mode 100644 index 000000000000..ab3cf7cb8c65 --- /dev/null +++ b/core/java/android/content/pm/parsing/AndroidPackage.aidl @@ -0,0 +1,21 @@ +/* +** +** Copyright 2019, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License") +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.content.pm.parsing; + +/* @hide */ +parcelable AndroidPackage; diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java new file mode 100644 index 000000000000..35df47431a91 --- /dev/null +++ b/core/java/android/content/pm/parsing/AndroidPackage.java @@ -0,0 +1,480 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.content.pm.parsing; + +import android.annotation.Nullable; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageParser; +import android.content.pm.PackageUserState; +import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.ArraySet; +import android.util.SparseArray; + +import java.security.PublicKey; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +/** + * The last state of a package during parsing/install before it is available in + * {@link com.android.server.pm.PackageManagerService#mPackages}. + * + * It is the responsibility of the caller to understand what data is available at what step of the + * parsing or install process. + * + * TODO(b/135203078): Nullability annotations + * TODO(b/135203078): Remove get/setAppInfo differences + * + * @hide + */ +public interface AndroidPackage extends Parcelable { + + /** + * This will eventually be removed. Avoid calling this at all costs. + */ + @Deprecated + AndroidPackageWrite mutate(); + + boolean canHaveOatDir(); + + boolean cantSaveState(); + + List<String> getAdoptPermissions(); + + List<String> getAllCodePaths(); + + List<String> getAllCodePathsExcludingResourceOnly(); + + String getAppComponentFactory(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getClassLoaderName()} + */ + @Deprecated + String getAppInfoClassLoaderName(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getCodePath()} + */ + @Deprecated + String getAppInfoCodePath(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getName()} + */ + @Deprecated + String getAppInfoName(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getPackageName()} + */ + @Deprecated + String getAppInfoPackageName(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getProcessName()} + */ + @Deprecated + String getAppInfoProcessName(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getCodePath()} + */ + @Deprecated + String getAppInfoResourcePath(); + + Bundle getAppMetaData(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getVolumeUuid()} + */ + @Deprecated + String getApplicationInfoVolumeUuid(); + + String getBackupAgentName(); + + int getBanner(); + + String getBaseCodePath(); + + int getBaseRevisionCode(); + + int getCategory(); + + String getClassLoaderName(); + + String getClassName(); + + String getCodePath(); + + int getCompatibleWidthLimitDp(); + + int getCompileSdkVersion(); + + String getCompileSdkVersionCodeName(); + + @Nullable + List<ConfigurationInfo> getConfigPreferences(); + + String getCpuAbiOverride(); + + String getCredentialProtectedDataDir(); + + String getDataDir(); + + int getDescriptionRes(); + + String getDeviceProtectedDataDir(); + + List<FeatureGroupInfo> getFeatureGroups(); + + int getFlags(); + + int getFullBackupContent(); + + int getHiddenApiEnforcementPolicy(); + + int getIcon(); + + int getIconRes(); + + List<String> getImplicitPermissions(); + + int getInstallLocation(); + + Map<String, ArraySet<PublicKey>> getKeySetMapping(); + + int getLabelRes(); + + int getLargestWidthLimitDp(); + + long[] getLastPackageUsageTimeInMills(); + + long getLatestForegroundPackageUseTimeInMills(); + + long getLatestPackageUseTimeInMills(); + + List<String> getLibraryNames(); + + int getLogo(); + + long getLongVersionCode(); + + String getManageSpaceActivityName(); + + String getManifestPackageName(); + + float getMaxAspectRatio(); + + Bundle getMetaData(); // TODO(b/135203078): Make all the Bundles immutable + + float getMinAspectRatio(); + + int getMinSdkVersion(); + + String getName(); + + String getNativeLibraryDir(); + + String getNativeLibraryRootDir(); + + int getNetworkSecurityConfigRes(); + + CharSequence getNonLocalizedLabel(); + + @Nullable + List<String> getOriginalPackages(); + + String getOverlayCategory(); + + int getOverlayPriority(); + + String getOverlayTarget(); + + String getOverlayTargetName(); + + /** + * Map of overlayable name to actor name. + */ + Map<String, String> getOverlayables(); + + // TODO(b/135203078): Does this and getAppInfoPackageName have to be separate methods? + // The refactor makes them the same value with no known consequences, so should be redundant. + String getPackageName(); + + @Nullable + List<ParsedActivity> getActivities(); + + @Nullable + List<ParsedInstrumentation> getInstrumentations(); + + @Nullable + List<ParsedPermissionGroup> getPermissionGroups(); + + @Nullable + List<ParsedPermission> getPermissions(); + + @Nullable + List<ParsedProvider> getProviders(); + + @Nullable + List<ParsedActivity> getReceivers(); + + @Nullable + List<ParsedService> getServices(); + + String getPermission(); + + @Nullable + List<ParsedActivityIntentInfo> getPreferredActivityFilters(); + + int getPreferredOrder(); + + String getPrimaryCpuAbi(); + + int getPrivateFlags(); + + String getProcessName(); + + @Nullable + List<String> getProtectedBroadcasts(); + + String getPublicSourceDir(); + + List<Intent> getQueriesIntents(); + + List<String> getQueriesPackages(); + + String getRealPackage(); + + // TODO(b/135203078): Rename to getRequiredFeatures? Somewhat ambiguous whether "Req" is + // required or requested. + @Nullable + List<FeatureInfo> getReqFeatures(); + + List<String> getRequestedPermissions(); + + String getRequiredAccountType(); + + int getRequiresSmallestWidthDp(); + + byte[] getRestrictUpdateHash(); + + String getRestrictedAccountType(); + + int getRoundIconRes(); + + String getScanPublicSourceDir(); + + String getScanSourceDir(); + + String getSeInfo(); + + String getSeInfoUser(); + + String getSecondaryCpuAbi(); + + String getSecondaryNativeLibraryDir(); + + String getSharedUserId(); + + int getSharedUserLabel(); + + PackageParser.SigningDetails getSigningDetails(); + + String[] getSplitClassLoaderNames(); + + @Nullable + String[] getSplitCodePaths(); + + @Nullable + SparseArray<int[]> getSplitDependencies(); + + int[] getSplitFlags(); + + String[] getSplitNames(); + + String[] getSplitPublicSourceDirs(); + + int[] getSplitRevisionCodes(); + + String getStaticSharedLibName(); + + long getStaticSharedLibVersion(); + + // TODO(b/135203078): Return String directly + UUID getStorageUuid(); + + int getTargetSandboxVersion(); + + int getTargetSdkVersion(); + + String getTaskAffinity(); + + int getTheme(); + + int getUiOptions(); + + int getUid(); + + Set<String> getUpgradeKeySets(); + + @Nullable + List<String> getUsesLibraries(); + + @Nullable + String[] getUsesLibraryFiles(); + + List<SharedLibraryInfo> getUsesLibraryInfos(); + + @Nullable + List<String> getUsesOptionalLibraries(); + + @Nullable + List<String> getUsesStaticLibraries(); + + @Nullable + String[][] getUsesStaticLibrariesCertDigests(); + + @Nullable + long[] getUsesStaticLibrariesVersions(); + + int getVersionCode(); + + int getVersionCodeMajor(); + + String getVersionName(); + + String getVolumeUuid(); + + String getZygotePreloadName(); + + boolean hasComponentClassName(String className); + + // App Info + + boolean hasRequestedLegacyExternalStorage(); + + boolean isBaseHardwareAccelerated(); + + boolean isCoreApp(); + + boolean isDefaultToDeviceProtectedStorage(); + + boolean isDirectBootAware(); + + boolean isEmbeddedDexUsed(); + + boolean isEnabled(); + + boolean isEncryptionAware(); + + boolean isExternal(); + + boolean isForceQueryable(); + + boolean isForwardLocked(); + + boolean isHiddenUntilInstalled(); + + boolean isInstantApp(); + + boolean isInternal(); + + boolean isLibrary(); + + // TODO(b/135203078): Should probably be in a utility class + boolean isMatch(int flags); + + boolean isNativeLibraryRootRequiresIsa(); + + boolean isOem(); + + boolean isOverlayIsStatic(); + + boolean isPrivileged(); + + boolean isProduct(); + + boolean isProfileableByShell(); + + boolean isRequiredForAllUsers(); + + boolean isStaticSharedLibrary(); + + boolean isStub(); + + boolean isSystem(); // TODO(b/135203078): Collapse with isSystemApp, should be exactly the same. + + boolean isSystemApp(); + + boolean isSystemExt(); + + boolean isUpdatedSystemApp(); + + boolean isUse32BitAbi(); + + boolean isVendor(); + + boolean isVisibleToInstantApps(); + + List<String> makeListAllCodePaths(); // TODO(b/135203078): Collapse with getAllCodePaths + + boolean requestsIsolatedSplitLoading(); + + /** + * Generates an {@link ApplicationInfo} object with only the data available in this object. + * + * This does not contain any system or user state data, and should be avoided. Prefer + * {@link PackageInfoUtils#generateApplicationInfo(AndroidPackage, int, PackageUserState, int)}. + */ + ApplicationInfo toAppInfoWithoutState(); + + Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() { + @Override + public PackageImpl createFromParcel(Parcel source) { + return new PackageImpl(source); + } + + @Override + public PackageImpl[] newArray(int size) { + return new PackageImpl[size]; + } + }; +} diff --git a/core/java/android/content/pm/parsing/AndroidPackageWrite.java b/core/java/android/content/pm/parsing/AndroidPackageWrite.java new file mode 100644 index 000000000000..b7595d2dd710 --- /dev/null +++ b/core/java/android/content/pm/parsing/AndroidPackageWrite.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing; + +import android.annotation.Nullable; +import android.content.pm.PackageParser; +import android.content.pm.SharedLibraryInfo; + +import java.util.List; + +/** + * Contains remaining mutable fields after package parsing has completed. + * + * Most are state that can probably be tracked outside of the AndroidPackage object. New methods + * should never be added to this interface. + * + * TODO(b/135203078): Remove entirely + * + * @deprecated the eventual goal is that the object returned from parsing represents exactly what + * was parsed from the APK, and so further mutation should be disallowed, + * with any state being stored in another class + * + * @hide + */ +@Deprecated +public interface AndroidPackageWrite extends AndroidPackage { + + AndroidPackageWrite setUsesLibraryFiles(@Nullable String[] usesLibraryFiles); + + // TODO(b/135203078): Remove or use a non-system wide representation of the shared libraries; + // this doesn't represent what was parsed from the APK + AndroidPackageWrite setUsesLibraryInfos(@Nullable List<SharedLibraryInfo> usesLibraryInfos); + + AndroidPackageWrite setHiddenUntilInstalled(boolean hidden); + + AndroidPackageWrite setUpdatedSystemApp(boolean updatedSystemApp); + + AndroidPackageWrite setLastPackageUsageTimeInMills(int reason, long time); + + AndroidPackageWrite setPrimaryCpuAbi(String primaryCpuAbi); + + AndroidPackageWrite setSeInfo(String seInfo); + + AndroidPackageWrite setSigningDetails(PackageParser.SigningDetails signingDetails); +} diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java new file mode 100644 index 000000000000..ac2e373f000d --- /dev/null +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing; + +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; + +import android.annotation.UnsupportedAppUsage; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.VerifierInfo; +import android.content.res.ApkAssets; +import android.content.res.XmlResourceParser; +import android.os.Trace; +import android.util.ArrayMap; +import android.util.AttributeSet; +import android.util.Pair; +import android.util.Slog; + +import com.android.internal.R; +import com.android.internal.util.ArrayUtils; + +import libcore.io.IoUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.IOException; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** @hide */ +public class ApkLiteParseUtils { + + private static final String TAG = ApkParseUtils.TAG; + + // TODO(b/135203078): Consolidate constants + private static final int DEFAULT_MIN_SDK_VERSION = 1; + private static final int DEFAULT_TARGET_SDK_VERSION = 0; + + private static final int PARSE_DEFAULT_INSTALL_LOCATION = + PackageInfo.INSTALL_LOCATION_UNSPECIFIED; + + /** + * Parse only lightweight details about the package at the given location. + * Automatically detects if the package is a monolithic style (single APK + * file) or cluster style (directory of APKs). + * <p> + * This performs sanity checking on cluster style packages, such as + * requiring identical package name and version codes, a single base APK, + * and unique split names. + * + * @see PackageParser#parsePackage(File, int) + */ + @UnsupportedAppUsage + public static PackageParser.PackageLite parsePackageLite(File packageFile, int flags) + throws PackageParser.PackageParserException { + if (packageFile.isDirectory()) { + return parseClusterPackageLite(packageFile, flags); + } else { + return parseMonolithicPackageLite(packageFile, flags); + } + } + + public static PackageParser.PackageLite parseMonolithicPackageLite(File packageFile, int flags) + throws PackageParser.PackageParserException { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite"); + final PackageParser.ApkLite baseApk = parseApkLite(packageFile, flags); + final String packagePath = packageFile.getAbsolutePath(); + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + return new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null, + null, null); + } + + public static PackageParser.PackageLite parseClusterPackageLite(File packageDir, int flags) + throws PackageParser.PackageParserException { + final File[] files = packageDir.listFiles(); + if (ArrayUtils.isEmpty(files)) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_NOT_APK, "No packages found in split"); + } + + String packageName = null; + int versionCode = 0; + + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite"); + final ArrayMap<String, PackageParser.ApkLite> apks = new ArrayMap<>(); + for (File file : files) { + if (PackageParser.isApkFile(file)) { + final PackageParser.ApkLite lite = parseApkLite(file, flags); + + // Assert that all package names and version codes are + // consistent with the first one we encounter. + if (packageName == null) { + packageName = lite.packageName; + versionCode = lite.versionCode; + } else { + if (!packageName.equals(lite.packageName)) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Inconsistent package " + lite.packageName + " in " + file + + "; expected " + packageName); + } + if (versionCode != lite.versionCode) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Inconsistent version " + lite.versionCode + " in " + file + + "; expected " + versionCode); + } + } + + // Assert that each split is defined only oncuses-static-libe + if (apks.put(lite.splitName, lite) != null) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Split name " + lite.splitName + + " defined more than once; most recent was " + file); + } + } + } + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + + final PackageParser.ApkLite baseApk = apks.remove(null); + if (baseApk == null) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Missing base APK in " + packageDir); + } + + // Always apply deterministic ordering based on splitName + final int size = apks.size(); + + String[] splitNames = null; + boolean[] isFeatureSplits = null; + String[] usesSplitNames = null; + String[] configForSplits = null; + String[] splitCodePaths = null; + int[] splitRevisionCodes = null; + if (size > 0) { + splitNames = new String[size]; + isFeatureSplits = new boolean[size]; + usesSplitNames = new String[size]; + configForSplits = new String[size]; + splitCodePaths = new String[size]; + splitRevisionCodes = new int[size]; + + splitNames = apks.keySet().toArray(splitNames); + Arrays.sort(splitNames, PackageParser.sSplitNameComparator); + + for (int i = 0; i < size; i++) { + final PackageParser.ApkLite apk = apks.get(splitNames[i]); + usesSplitNames[i] = apk.usesSplitName; + isFeatureSplits[i] = apk.isFeatureSplit; + configForSplits[i] = apk.configForSplit; + splitCodePaths[i] = apk.codePath; + splitRevisionCodes[i] = apk.revisionCode; + } + } + + final String codePath = packageDir.getAbsolutePath(); + return new PackageParser.PackageLite(codePath, baseApk, splitNames, isFeatureSplits, + usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes); + } + + /** + * Utility method that retrieves lightweight details about a single APK + * file, including package name, split name, and install location. + * + * @param apkFile path to a single APK + * @param flags optional parse flags, such as + * {@link PackageParser#PARSE_COLLECT_CERTIFICATES} + */ + public static PackageParser.ApkLite parseApkLite(File apkFile, int flags) + throws PackageParser.PackageParserException { + return parseApkLiteInner(apkFile, null, null, flags); + } + + /** + * Utility method that retrieves lightweight details about a single APK + * file, including package name, split name, and install location. + * + * @param fd already open file descriptor of an apk file + * @param debugPathName arbitrary text name for this file, for debug output + * @param flags optional parse flags, such as + * {@link PackageParser#PARSE_COLLECT_CERTIFICATES} + */ + public static PackageParser.ApkLite parseApkLite(FileDescriptor fd, String debugPathName, + int flags) throws PackageParser.PackageParserException { + return parseApkLiteInner(null, fd, debugPathName, flags); + } + + private static PackageParser.ApkLite parseApkLiteInner(File apkFile, FileDescriptor fd, + String debugPathName, int flags) throws PackageParser.PackageParserException { + final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath(); + + XmlResourceParser parser = null; + ApkAssets apkAssets = null; + try { + try { + apkAssets = fd != null + ? ApkAssets.loadFromFd(fd, debugPathName, false, false) + : ApkAssets.loadFromPath(apkPath); + } catch (IOException e) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_NOT_APK, + "Failed to parse " + apkPath, e); + } + + parser = apkAssets.openXml(PackageParser.ANDROID_MANIFEST_FILENAME); + + final PackageParser.SigningDetails signingDetails; + if ((flags & PackageParser.PARSE_COLLECT_CERTIFICATES) != 0) { + final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0; + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); + try { + signingDetails = + ApkParseUtils.collectCertificates(apkFile.getAbsolutePath(), skipVerify, + false, PackageParser.SigningDetails.UNKNOWN); + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } else { + signingDetails = PackageParser.SigningDetails.UNKNOWN; + } + + final AttributeSet attrs = parser; + return parseApkLite(apkPath, parser, attrs, signingDetails); + + } catch (XmlPullParserException | IOException | RuntimeException e) { + Slog.w(TAG, "Failed to parse " + apkPath, e); + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to parse " + apkPath, e); + } finally { + IoUtils.closeQuietly(parser); + if (apkAssets != null) { + try { + apkAssets.close(); + } catch (Throwable ignored) { + } + } + // TODO(b/72056911): Implement AutoCloseable on ApkAssets. + } + } + + private static PackageParser.ApkLite parseApkLite( + String codePath, XmlPullParser parser, AttributeSet attrs, + PackageParser.SigningDetails signingDetails) + throws IOException, XmlPullParserException, PackageParser.PackageParserException { + final Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames( + parser, attrs); + + int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; + int versionCode = 0; + int versionCodeMajor = 0; + int targetSdkVersion = DEFAULT_TARGET_SDK_VERSION; + int minSdkVersion = DEFAULT_MIN_SDK_VERSION; + int revisionCode = 0; + boolean coreApp = false; + boolean debuggable = false; + boolean multiArch = false; + boolean use32bitAbi = false; + boolean extractNativeLibs = true; + boolean isolatedSplits = false; + boolean isFeatureSplit = false; + boolean isSplitRequired = false; + boolean useEmbeddedDex = false; + String configForSplit = null; + String usesSplitName = null; + + for (int i = 0; i < attrs.getAttributeCount(); i++) { + final String attr = attrs.getAttributeName(i); + switch (attr) { + case "installLocation": + installLocation = attrs.getAttributeIntValue(i, + PARSE_DEFAULT_INSTALL_LOCATION); + break; + case "versionCode": + versionCode = attrs.getAttributeIntValue(i, 0); + break; + case "versionCodeMajor": + versionCodeMajor = attrs.getAttributeIntValue(i, 0); + break; + case "revisionCode": + revisionCode = attrs.getAttributeIntValue(i, 0); + break; + case "coreApp": + coreApp = attrs.getAttributeBooleanValue(i, false); + break; + case "isolatedSplits": + isolatedSplits = attrs.getAttributeBooleanValue(i, false); + break; + case "configForSplit": + configForSplit = attrs.getAttributeValue(i); + break; + case "isFeatureSplit": + isFeatureSplit = attrs.getAttributeBooleanValue(i, false); + break; + case "isSplitRequired": + isSplitRequired = attrs.getAttributeBooleanValue(i, false); + break; + } + } + + // Only search the tree when the tag is the direct child of <manifest> tag + int type; + final int searchDepth = parser.getDepth() + 1; + + final List<VerifierInfo> verifiers = new ArrayList<>(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + if (parser.getDepth() != searchDepth) { + continue; + } + + if (PackageParser.TAG_PACKAGE_VERIFIER.equals(parser.getName())) { + final VerifierInfo verifier = parseVerifier(attrs); + if (verifier != null) { + verifiers.add(verifier); + } + } else if (PackageParser.TAG_APPLICATION.equals(parser.getName())) { + for (int i = 0; i < attrs.getAttributeCount(); ++i) { + final String attr = attrs.getAttributeName(i); + switch (attr) { + case "debuggable": + debuggable = attrs.getAttributeBooleanValue(i, false); + break; + case "multiArch": + multiArch = attrs.getAttributeBooleanValue(i, false); + break; + case "use32bitAbi": + use32bitAbi = attrs.getAttributeBooleanValue(i, false); + break; + case "extractNativeLibs": + extractNativeLibs = attrs.getAttributeBooleanValue(i, true); + break; + case "useEmbeddedDex": + useEmbeddedDex = attrs.getAttributeBooleanValue(i, false); + break; + } + } + } else if (PackageParser.TAG_USES_SPLIT.equals(parser.getName())) { + if (usesSplitName != null) { + Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others."); + continue; + } + + usesSplitName = attrs.getAttributeValue(PackageParser.ANDROID_RESOURCES, "name"); + if (usesSplitName == null) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "<uses-split> tag requires 'android:name' attribute"); + } + } else if (PackageParser.TAG_USES_SDK.equals(parser.getName())) { + for (int i = 0; i < attrs.getAttributeCount(); ++i) { + final String attr = attrs.getAttributeName(i); + if ("targetSdkVersion".equals(attr)) { + targetSdkVersion = attrs.getAttributeIntValue(i, + DEFAULT_TARGET_SDK_VERSION); + } + if ("minSdkVersion".equals(attr)) { + minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION); + } + } + } + } + + return new PackageParser.ApkLite(codePath, packageSplit.first, packageSplit.second, + isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode, + versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails, + coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs, + isolatedSplits, minSdkVersion, targetSdkVersion); + } + + public static VerifierInfo parseVerifier(AttributeSet attrs) { + String packageName = null; + String encodedPublicKey = null; + + final int attrCount = attrs.getAttributeCount(); + for (int i = 0; i < attrCount; i++) { + final int attrResId = attrs.getAttributeNameResource(i); + switch (attrResId) { + case R.attr.name: + packageName = attrs.getAttributeValue(i); + break; + + case R.attr.publicKey: + encodedPublicKey = attrs.getAttributeValue(i); + break; + } + } + + if (packageName == null || packageName.length() == 0) { + Slog.i(TAG, "verifier package name was null; skipping"); + return null; + } + + final PublicKey publicKey = PackageParser.parsePublicKey(encodedPublicKey); + if (publicKey == null) { + Slog.i(TAG, "Unable to parse verifier public key for " + packageName); + return null; + } + + return new VerifierInfo(packageName, publicKey); + } +} diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java new file mode 100644 index 000000000000..ffddbb6c2c47 --- /dev/null +++ b/core/java/android/content/pm/parsing/ApkParseUtils.java @@ -0,0 +1,3204 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing; + +import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.content.pm.PackageManager.FEATURE_WATCH; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; +import static android.os.Build.VERSION_CODES.O; +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; +import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityTaskManager; +import android.app.ActivityThread; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.PackageParser.SigningDetails; +import android.content.pm.Signature; +import android.content.pm.permission.SplitPermissionInfoParcelable; +import android.content.pm.split.DefaultSplitAssetLoader; +import android.content.pm.split.SplitAssetDependencyLoader; +import android.content.pm.split.SplitAssetLoader; +import android.content.res.ApkAssets; +import android.content.res.AssetManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.FileUtils; +import android.os.RemoteException; +import android.os.SystemProperties; +import android.os.Trace; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Pair; +import android.util.Slog; +import android.util.SparseArray; +import android.util.TypedValue; +import android.util.apk.ApkSignatureVerifier; + +import com.android.internal.R; +import com.android.internal.os.ClassLoaderFactory; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.XmlUtils; + +import libcore.io.IoUtils; +import libcore.util.EmptyArray; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.IOException; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** @hide */ +public class ApkParseUtils { + + // TODO(b/135203078): Consolidate log tags + static final String TAG = "PackageParsing"; + + /** + * Parse the package at the given location. Automatically detects if the + * package is a monolithic style (single APK file) or cluster style + * (directory of APKs). + * <p> + * This performs sanity checking on cluster style packages, such as + * requiring identical package name and version codes, a single base APK, + * and unique split names. + * <p> + * Note that this <em>does not</em> perform signature verification; that + * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}. + * + * If {@code useCaches} is true, the package parser might return a cached + * result from a previous parse of the same {@code packageFile} with the same + * {@code flags}. Note that this method does not check whether {@code packageFile} + * has changed since the last parse, it's up to callers to do so. + * + * @see PackageParser#parsePackageLite(File, int) + */ + public static ParsingPackage parsePackage( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + DisplayMetrics displayMetrics, + boolean onlyCoreApps, + File packageFile, + int flags + ) throws PackageParserException { + if (packageFile.isDirectory()) { + return parseClusterPackage(parseInput, separateProcesses, callback, displayMetrics, + onlyCoreApps, packageFile, flags); + } else { + return parseMonolithicPackage(parseInput, separateProcesses, callback, displayMetrics, + onlyCoreApps, packageFile, flags); + } + } + + /** + * Parse all APKs contained in the given directory, treating them as a + * single package. This also performs sanity checking, such as requiring + * identical package name and version codes, a single base APK, and unique + * split names. + * <p> + * Note that this <em>does not</em> perform signature verification; that + * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}. + */ + private static ParsingPackage parseClusterPackage( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + DisplayMetrics displayMetrics, + boolean onlyCoreApps, + File packageDir, + int flags + ) throws PackageParserException { + final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir, + 0); + if (onlyCoreApps && !lite.coreApp) { + throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Not a coreApp: " + packageDir); + } + + // Build the split dependency tree. + SparseArray<int[]> splitDependencies = null; + final SplitAssetLoader assetLoader; + if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) { + try { + splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite); + assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags); + } catch (SplitAssetDependencyLoader.IllegalDependencyException e) { + throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage()); + } + } else { + assetLoader = new DefaultSplitAssetLoader(lite, flags); + } + + try { + final AssetManager assets = assetLoader.getBaseAssetManager(); + final File baseApk = new File(lite.baseCodePath); + ParsingPackage parsingPackage = parseBaseApk(parseInput, separateProcesses, callback, + displayMetrics, baseApk, assets, flags); + if (parsingPackage == null) { + throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, + "Failed to parse base APK: " + baseApk); + } + + if (!ArrayUtils.isEmpty(lite.splitNames)) { + parsingPackage.asSplit( + lite.splitNames, + lite.splitCodePaths, + lite.splitRevisionCodes, + splitDependencies + ); + final int num = lite.splitNames.length; + + for (int i = 0; i < num; i++) { + final AssetManager splitAssets = assetLoader.getSplitAssetManager(i); + parseSplitApk(parseInput, displayMetrics, separateProcesses, parsingPackage, i, + splitAssets, flags); + } + } + + return parsingPackage.setCodePath(packageDir.getCanonicalPath()) + .setUse32BitAbi(lite.use32bitAbi); + } catch (IOException e) { + throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to get path: " + lite.baseCodePath, e); + } finally { + IoUtils.closeQuietly(assetLoader); + } + } + + /** + * Parse the given APK file, treating it as as a single monolithic package. + * <p> + * Note that this <em>does not</em> perform signature verification; that + * must be done separately in {@link #collectCertificates(AndroidPackage, boolean)}. + */ + public static ParsingPackage parseMonolithicPackage( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + DisplayMetrics displayMetrics, + boolean onlyCoreApps, + File apkFile, + int flags + ) throws PackageParserException { + final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile, + flags); + if (onlyCoreApps) { + if (!lite.coreApp) { + throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Not a coreApp: " + apkFile); + } + } + + final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags); + try { + return parseBaseApk(parseInput, separateProcesses, callback, + displayMetrics, apkFile, assetLoader.getBaseAssetManager(), flags) + .setCodePath(apkFile.getCanonicalPath()) + .setUse32BitAbi(lite.use32bitAbi); + } catch (IOException e) { + throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to get path: " + apkFile, e); + } finally { + IoUtils.closeQuietly(assetLoader); + } + } + + private static ParsingPackage parseBaseApk( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + DisplayMetrics displayMetrics, + File apkFile, + AssetManager assets, + int flags + ) throws PackageParserException { + final String apkPath = apkFile.getAbsolutePath(); + + String volumeUuid = null; + if (apkPath.startsWith(PackageParser.MNT_EXPAND)) { + final int end = apkPath.indexOf('/', PackageParser.MNT_EXPAND.length()); + volumeUuid = apkPath.substring(PackageParser.MNT_EXPAND.length(), end); + } + + if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); + + XmlResourceParser parser = null; + try { + final int cookie = assets.findCookieForPath(apkPath); + if (cookie == 0) { + throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Failed adding asset path: " + apkPath); + } + parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME); + final Resources res = new Resources(assets, displayMetrics, null); + + ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath, res, + parser, flags); + if (!result.isSuccess()) { + throw new PackageParserException(result.getParseError(), + apkPath + " (at " + parser.getPositionDescription() + "): " + + result.getErrorMessage()); + } + + ParsingPackage pkg = result.getResultAndNull(); + ApkAssets apkAssets = assets.getApkAssets()[0]; + if (apkAssets.definesOverlayable()) { + SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers(); + int size = packageNames.size(); + for (int index = 0; index < size; index++) { + String packageName = packageNames.get(index); + Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName); + if (overlayableToActor != null && !overlayableToActor.isEmpty()) { + for (String overlayable : overlayableToActor.keySet()) { + pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable)); + } + } + } + } + + return pkg.setVolumeUuid(volumeUuid) + .setApplicationVolumeUuid(volumeUuid) + .setSigningDetails(SigningDetails.UNKNOWN); + } catch (PackageParserException e) { + throw e; + } catch (Exception e) { + throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to read manifest from " + apkPath, e); + } finally { + IoUtils.closeQuietly(parser); + } + } + + private static void parseSplitApk( + ParseInput parseInput, + DisplayMetrics displayMetrics, + String[] separateProcesses, + ParsingPackage parsingPackage, + int splitIndex, + AssetManager assets, + int flags + ) throws PackageParserException { + final String apkPath = parsingPackage.getSplitCodePaths()[splitIndex]; + + if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); + + final Resources res; + XmlResourceParser parser = null; + try { + // This must always succeed, as the path has been added to the AssetManager before. + final int cookie = assets.findCookieForPath(apkPath); + if (cookie == 0) { + throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Failed adding asset path: " + apkPath); + } + + parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME); + res = new Resources(assets, displayMetrics, null); + + final String[] outError = new String[1]; + ParseResult parseResult = parseSplitApk(parseInput, separateProcesses, parsingPackage, + res, parser, flags, splitIndex, outError); + if (!parseResult.isSuccess()) { + throw new PackageParserException(parseResult.getParseError(), + apkPath + " (at " + parser.getPositionDescription() + "): " + + parseResult.getErrorMessage()); + } + } catch (PackageParserException e) { + throw e; + } catch (Exception e) { + throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to read manifest from " + apkPath, e); + } finally { + IoUtils.closeQuietly(parser); + } + } + + /** + * Parse the manifest of a <em>base APK</em>. When adding new features you + * need to consider whether they should be supported by split APKs and child + * packages. + * + * @param apkPath The package apk file path + * @param res The resources from which to resolve values + * @param parser The manifest parser + * @param flags Flags how to parse + * @return Parsed package or null on error. + */ + private static ParseResult parseBaseApk( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + String apkPath, + Resources res, + XmlResourceParser parser, + int flags + ) throws XmlPullParserException, IOException { + final String splitName; + final String pkgName; + + try { + Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(parser, + parser); + pkgName = packageSplit.first; + splitName = packageSplit.second; + + if (!TextUtils.isEmpty(splitName)) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, + "Expected base APK, but found split " + splitName + ); + } + } catch (PackageParserException e) { + return parseInput.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME); + } + + TypedArray manifestArray = null; + + try { + manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest); + + boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false); + + ParsingPackage parsingPackage = PackageImpl.forParsing( + pkgName, + apkPath, + manifestArray, + isCoreApp + ); + + ParseResult result = parseBaseApkTags(parseInput, separateProcesses, callback, + parsingPackage, manifestArray, res, parser, flags); + if (!result.isSuccess()) { + return result; + } + + return parseInput.success(parsingPackage); + } finally { + if (manifestArray != null) { + manifestArray.recycle(); + } + } + } + + /** + * Parse the manifest of a <em>split APK</em>. + * <p> + * Note that split APKs have many more restrictions on what they're capable + * of doing, so many valid features of a base APK have been carefully + * omitted here. + * + * @param parsingPackage builder to fill + * @return false on failure + */ + private static ParseResult parseSplitApk( + ParseInput parseInput, + String[] separateProcesses, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + int flags, + int splitIndex, + String[] outError + ) throws XmlPullParserException, IOException, PackageParserException { + AttributeSet attrs = parser; + + // We parsed manifest tag earlier; just skip past it + PackageParser.parsePackageSplitNames(parser, attrs); + + int type; + + boolean foundApp = false; + + int outerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals(PackageParser.TAG_APPLICATION)) { + if (foundApp) { + if (PackageParser.RIGID_PARSER) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "<manifest> has more than one <application>" + ); + } else { + Slog.w(TAG, "<manifest> has more than one <application>"); + XmlUtils.skipCurrentTag(parser); + continue; + } + } + + foundApp = true; + ParseResult parseResult = parseSplitApplication(parseInput, separateProcesses, + parsingPackage, res, + parser, flags, + splitIndex, outError); + if (!parseResult.isSuccess()) { + return parseResult; + } + + } else if (PackageParser.RIGID_PARSER) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad element under <manifest>: " + parser.getName() + ); + + } else { + Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + } + + if (!foundApp) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY, + "<manifest> does not contain an <application>" + ); + } + + return parseInput.success(parsingPackage); + } + + /** + * Parse the {@code application} XML tree at the current parse location in a + * <em>split APK</em> manifest. + * <p> + * Note that split APKs have many more restrictions on what they're capable + * of doing, so many valid features of a base APK have been carefully + * omitted here. + */ + private static ParseResult parseSplitApplication( + ParseInput parseInput, + String[] separateProcesses, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + int flags, + int splitIndex, + String[] outError + ) throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication); + + parsingPackage.setSplitHasCode(splitIndex, sa.getBoolean( + R.styleable.AndroidManifestApplication_hasCode, true)); + + final String classLoaderName = sa.getString( + R.styleable.AndroidManifestApplication_classLoader); + if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) { + parsingPackage.setSplitClassLoaderName(splitIndex, classLoaderName); + } else { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Invalid class loader name: " + classLoaderName + ); + } + + final int innerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + ComponentParseUtils.ParsedComponent parsedComponent = null; + + String tagName = parser.getName(); + switch (tagName) { + case "activity": + ComponentParseUtils.ParsedActivity activity = + ComponentParseUtils.parseActivity(separateProcesses, + parsingPackage, + res, parser, flags, + outError, + false, + parsingPackage.isBaseHardwareAccelerated()); + if (activity == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addActivity(activity); + parsedComponent = activity; + break; + case "receiver": + activity = ComponentParseUtils.parseActivity( + separateProcesses, parsingPackage, + res, parser, flags, outError, + true, false); + if (activity == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addReceiver(activity); + parsedComponent = activity; + break; + case "service": + ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService( + separateProcesses, + parsingPackage, + res, parser, flags, outError + ); + if (s == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addService(s); + parsedComponent = s; + break; + case "provider": + ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider( + separateProcesses, + parsingPackage, + res, parser, flags, outError); + if (p == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addProvider(p); + parsedComponent = p; + break; + case "activity-alias": + activity = ComponentParseUtils.parseActivityAlias( + parsingPackage, + res, + parser, + outError + ); + if (activity == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addActivity(activity); + parsedComponent = activity; + break; + case "meta-data": + // note: application meta-data is stored off to the side, so it can + // remain null in the primary copy (we like to avoid extra copies because + // it can be large) + Bundle appMetaData = parseMetaData(parsingPackage, res, parser, + parsingPackage.getAppMetaData(), + outError); + if (appMetaData == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.setAppMetaData(appMetaData); + break; + case "uses-static-library": + ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage, + res, parser); + if (!parseResult.isSuccess()) { + return parseResult; + } + + break; + case "uses-library": + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesLibrary); + + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestUsesLibrary_name); + boolean req = sa.getBoolean( + R.styleable.AndroidManifestUsesLibrary_required, true); + + sa.recycle(); + + if (lname != null) { + lname = lname.intern(); + if (req) { + // Upgrade to treat as stronger constraint + parsingPackage.addUsesLibrary(lname) + .removeUsesOptionalLibrary(lname); + } else { + // Ignore if someone already defined as required + if (!ArrayUtils.contains(parsingPackage.getUsesLibraries(), lname)) { + parsingPackage.addUsesOptionalLibrary(lname); + } + } + } + + XmlUtils.skipCurrentTag(parser); + break; + case "uses-package": + // Dependencies for app installers; we don't currently try to + // enforce this. + XmlUtils.skipCurrentTag(parser); + break; + default: + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <application>: " + tagName + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad element under <application>: " + tagName + ); + } + } + + if (parsedComponent != null && parsedComponent.getSplitName() == null) { + // If the loaded component did not specify a split, inherit the split name + // based on the split it is defined in. + // This is used to later load the correct split when starting this + // component. + parsedComponent.setSplitName(parsingPackage.getSplitNames()[splitIndex]); + } + } + + return parseInput.success(parsingPackage); + } + + private static ParseResult parseBaseApkTags( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + ParsingPackage parsingPackage, + TypedArray manifestArray, + Resources res, + XmlResourceParser parser, + int flags + ) throws XmlPullParserException, IOException { + int type; + boolean foundApp = false; + + TypedArray sa = manifestArray; + + ParseResult sharedUserResult = parseSharedUser(parseInput, parsingPackage, sa); + if (!sharedUserResult.isSuccess()) { + return sharedUserResult; + } + + parseManifestAttributes(sa, parsingPackage, flags); + + int outerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + + // All methods return a boolean, even if they can't fail. This can be enforced + // by making this final and not assigned, forcing the switch to assign success + // once in every branch. + final boolean success; + ParseResult parseResult = null; + + // TODO(b/135203078): Either use all booleans or all ParseResults + // TODO(b/135203078): Convert to instance methods to share variables + switch (tagName) { + case PackageParser.TAG_APPLICATION: + if (foundApp) { + if (PackageParser.RIGID_PARSER) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "<manifest> has more than one <application>" + ); + } else { + Slog.w(TAG, "<manifest> has more than one <application>"); + XmlUtils.skipCurrentTag(parser); + success = true; + } + } else { + foundApp = true; + parseResult = parseBaseApplication(parseInput, separateProcesses, + callback, + parsingPackage, res, parser, flags); + success = parseResult.isSuccess(); + } + break; + case PackageParser.TAG_OVERLAY: + parseResult = parseOverlay(parseInput, parsingPackage, res, parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_KEY_SETS: + parseResult = parseKeySets(parseInput, parsingPackage, res, parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_PERMISSION_GROUP: + parseResult = parsePermissionGroup(parseInput, parsingPackage, res, + parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_PERMISSION: + parseResult = parsePermission(parseInput, parsingPackage, res, parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_PERMISSION_TREE: + parseResult = parsePermissionTree(parseInput, parsingPackage, res, parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_USES_PERMISSION: + case PackageParser.TAG_USES_PERMISSION_SDK_M: + case PackageParser.TAG_USES_PERMISSION_SDK_23: + parseResult = parseUsesPermission(parseInput, parsingPackage, res, parser, + callback); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_USES_CONFIGURATION: + success = parseUsesConfiguration(parsingPackage, res, parser); + break; + case PackageParser.TAG_USES_FEATURE: + success = parseUsesFeature(parsingPackage, res, parser); + break; + case PackageParser.TAG_FEATURE_GROUP: + success = parseFeatureGroup(parsingPackage, res, parser); + break; + case PackageParser.TAG_USES_SDK: + parseResult = parseUsesSdk(parseInput, parsingPackage, res, parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_SUPPORT_SCREENS: + success = parseSupportScreens(parsingPackage, res, parser); + break; + case PackageParser.TAG_PROTECTED_BROADCAST: + success = parseProtectedBroadcast(parsingPackage, res, parser); + break; + case PackageParser.TAG_INSTRUMENTATION: + parseResult = parseInstrumentation(parseInput, parsingPackage, res, + parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_ORIGINAL_PACKAGE: + success = parseOriginalPackage(parsingPackage, res, parser); + break; + case PackageParser.TAG_ADOPT_PERMISSIONS: + success = parseAdoptPermissions(parsingPackage, res, parser); + break; + case PackageParser.TAG_USES_GL_TEXTURE: + case PackageParser.TAG_COMPATIBLE_SCREENS: + case PackageParser.TAG_SUPPORTS_INPUT: + case PackageParser.TAG_EAT_COMMENT: + // Just skip this tag + XmlUtils.skipCurrentTag(parser); + success = true; + break; + case PackageParser.TAG_RESTRICT_UPDATE: + success = parseRestrictUpdateHash(flags, parsingPackage, res, parser); + break; + case PackageParser.TAG_QUERIES: + parseResult = parseQueries(parseInput, parsingPackage, res, parser); + success = parseResult.isSuccess(); + break; + default: + parseResult = parseUnknownTag(parseInput, parsingPackage, parser); + success = parseResult.isSuccess(); + break; + } + + if (parseResult != null && !parseResult.isSuccess()) { + return parseResult; + } + + if (!success) { + return parseResult; + } + } + + if (!foundApp && ArrayUtils.size(parsingPackage.getInstrumentations()) == 0) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY, + "<manifest> does not contain an <application> or <instrumentation>" + ); + } + + convertNewPermissions(parsingPackage); + + convertSplitPermissions(parsingPackage); + + // At this point we can check if an application is not supporting densities and hence + // cannot be windowed / resized. Note that an SDK version of 0 is common for + // pre-Doughnut applications. + if (parsingPackage.usesCompatibilityMode()) { + adjustPackageToBeUnresizeableAndUnpipable(parsingPackage); + } + + return parseInput.success(parsingPackage); + } + + private static ParseResult parseUnknownTag( + ParseInput parseInput, + ParsingPackage parsingPackage, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + if (PackageParser.RIGID_PARSER) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad element under <manifest>: " + parser.getName() + ); + } else { + Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + return parseInput.success(parsingPackage); + } + } + + private static ParseResult parseSharedUser( + ParseInput parseInput, + ParsingPackage parsingPackage, + TypedArray manifestArray + ) { + String str = manifestArray.getNonConfigurationString( + R.styleable.AndroidManifest_sharedUserId, 0); + if (TextUtils.isEmpty(str)) { + return parseInput.success(parsingPackage); + } + + String nameError = validateName(str, true, true); + if (nameError != null && !"android".equals(parsingPackage.getPackageName())) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, + "<manifest> specifies bad sharedUserId name \"" + str + "\": " + + nameError + ); + } + + int sharedUserLabel = manifestArray.getResourceId( + R.styleable.AndroidManifest_sharedUserLabel, 0); + parsingPackage.setSharedUserId(str.intern()) + .setSharedUserLabel(sharedUserLabel); + + return parseInput.success(parsingPackage); + } + + private static void parseManifestAttributes( + TypedArray manifestArray, + ParsingPackage parsingPackage, + int flags + ) { + int installLocation = manifestArray.getInteger(R.styleable.AndroidManifest_installLocation, + PackageParser.PARSE_DEFAULT_INSTALL_LOCATION); + + final int targetSandboxVersion = manifestArray.getInteger( + R.styleable.AndroidManifest_targetSandboxVersion, + PackageParser.PARSE_DEFAULT_TARGET_SANDBOX); + + parsingPackage.setInstallLocation(installLocation) + .setTargetSandboxVersion(targetSandboxVersion); + + /* Set the global "on SD card" flag */ + parsingPackage.setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0); + + parsingPackage.setIsolatedSplitLoading(manifestArray.getBoolean( + R.styleable.AndroidManifest_isolatedSplits, false)); + } + + private static ParseResult parseKeySets( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws XmlPullParserException, IOException { + // we've encountered the 'key-sets' tag + // all the keys and keysets that we want must be defined here + // so we're going to iterate over the parser and pull out the things we want + int outerDepth = parser.getDepth(); + int currentKeySetDepth = -1; + int type; + String currentKeySet = null; + ArrayMap<String, PublicKey> publicKeys = new ArrayMap<>(); + ArraySet<String> upgradeKeySets = new ArraySet<>(); + ArrayMap<String, ArraySet<String>> definedKeySets = + new ArrayMap<>(); + ArraySet<String> improperKeySets = new ArraySet<>(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG) { + if (parser.getDepth() == currentKeySetDepth) { + currentKeySet = null; + currentKeySetDepth = -1; + } + continue; + } + String tagName = parser.getName(); + if (tagName.equals("key-set")) { + if (currentKeySet != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Improperly nested 'key-set' tag at " + parser.getPositionDescription() + ); + } + final TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestKeySet); + final String keysetName = sa.getNonResourceString( + R.styleable.AndroidManifestKeySet_name); + definedKeySets.put(keysetName, new ArraySet<>()); + currentKeySet = keysetName; + currentKeySetDepth = parser.getDepth(); + sa.recycle(); + } else if (tagName.equals("public-key")) { + if (currentKeySet == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Improperly nested 'key-set' tag at " + parser.getPositionDescription() + ); + } + final TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestPublicKey); + final String publicKeyName = sa.getNonResourceString( + R.styleable.AndroidManifestPublicKey_name); + final String encodedKey = sa.getNonResourceString( + R.styleable.AndroidManifestPublicKey_value); + if (encodedKey == null && publicKeys.get(publicKeyName) == null) { + sa.recycle(); + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "'public-key' " + publicKeyName + " must define a public-key value" + + " on first use at " + parser.getPositionDescription() + ); + } else if (encodedKey != null) { + PublicKey currentKey = PackageParser.parsePublicKey(encodedKey); + if (currentKey == null) { + Slog.w(TAG, "No recognized valid key in 'public-key' tag at " + + parser.getPositionDescription() + " key-set " + currentKeySet + + " will not be added to the package's defined key-sets."); + sa.recycle(); + improperKeySets.add(currentKeySet); + XmlUtils.skipCurrentTag(parser); + continue; + } + if (publicKeys.get(publicKeyName) == null + || publicKeys.get(publicKeyName).equals(currentKey)) { + + /* public-key first definition, or matches old definition */ + publicKeys.put(publicKeyName, currentKey); + } else { + sa.recycle(); + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Value of 'public-key' " + publicKeyName + + " conflicts with previously defined value at " + + parser.getPositionDescription() + ); + } + } + definedKeySets.get(currentKeySet).add(publicKeyName); + sa.recycle(); + XmlUtils.skipCurrentTag(parser); + } else if (tagName.equals("upgrade-key-set")) { + final TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUpgradeKeySet); + String name = sa.getNonResourceString( + R.styleable.AndroidManifestUpgradeKeySet_name); + upgradeKeySets.add(name); + sa.recycle(); + XmlUtils.skipCurrentTag(parser); + } else if (PackageParser.RIGID_PARSER) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad element under <key-sets>: " + parser.getName() + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription() + ); + } else { + Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName() + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + } + String packageName = parsingPackage.getPackageName(); + Set<String> publicKeyNames = publicKeys.keySet(); + if (publicKeyNames.removeAll(definedKeySets.keySet())) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Package" + packageName + " AndroidManifest.xml " + + "'key-set' and 'public-key' names must be distinct." + ); + } + + for (ArrayMap.Entry<String, ArraySet<String>> e : definedKeySets.entrySet()) { + final String keySetName = e.getKey(); + if (e.getValue().size() == 0) { + Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml " + + "'key-set' " + keySetName + " has no valid associated 'public-key'." + + " Not including in package's defined key-sets."); + continue; + } else if (improperKeySets.contains(keySetName)) { + Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml " + + "'key-set' " + keySetName + " contained improper 'public-key'" + + " tags. Not including in package's defined key-sets."); + continue; + } + + for (String s : e.getValue()) { + parsingPackage.addKeySet(keySetName, publicKeys.get(s)); + } + } + if (parsingPackage.getKeySetMapping().keySet().containsAll(upgradeKeySets)) { + parsingPackage.setUpgradeKeySets(upgradeKeySets); + } else { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Package" + packageName + " AndroidManifest.xml " + + "does not define all 'upgrade-key-set's ." + ); + } + + return parseInput.success(parsingPackage); + } + + public static boolean parsePackageItemInfo(String packageName, PackageItemInfo outInfo, + String[] outError, String tag, TypedArray sa, boolean nameRequired, + int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) { + // This case can only happen in unit tests where we sometimes need to create fakes + // of various package parser data structures. + if (sa == null) { + outError[0] = tag + " does not contain any attributes"; + return false; + } + + String name = sa.getNonConfigurationString(nameRes, 0); + if (name == null) { + if (nameRequired) { + outError[0] = tag + " does not specify android:name"; + return false; + } + } else { + String outInfoName = buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) { + outError[0] = tag + " invalid android:name"; + return false; + } + outInfo.name = outInfoName; + if (outInfoName == null) { + return false; + } + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0; + if (roundIconVal != 0) { + outInfo.icon = roundIconVal; + outInfo.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(iconRes, 0); + if (iconVal != 0) { + outInfo.icon = iconVal; + outInfo.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(logoRes, 0); + if (logoVal != 0) { + outInfo.logo = logoVal; + } + + int bannerVal = sa.getResourceId(bannerRes, 0); + if (bannerVal != 0) { + outInfo.banner = bannerVal; + } + + TypedValue v = sa.peekValue(labelRes); + if (v != null && (outInfo.labelRes = v.resourceId) == 0) { + outInfo.nonLocalizedLabel = v.coerceToString(); + } + + outInfo.packageName = packageName; + + return true; + } + + private static ParseResult parsePackageItemInfo( + ParseInput parseInput, + ParsingPackage parsingPackage, + String tag, + TypedArray sa, + boolean nameRequired, + int nameRes, + int labelRes, + int iconRes, + int roundIconRes, + int logoRes, + int bannerRes + ) { + // This case can only happen in unit tests where we sometimes need to create fakes + // of various package parser data structures. + if (sa == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + tag + " does not contain any attributes" + ); + } + + String name = sa.getNonConfigurationString(nameRes, 0); + if (name == null) { + if (nameRequired) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + tag + " does not specify android:name" + ); + } + } else { + String packageName = parsingPackage.getPackageName(); + String outInfoName = buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + tag + " invalid android:name" + ); + } else if (outInfoName == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Empty class name in package " + packageName + ); + } + + parsingPackage.setName(outInfoName); + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0; + if (roundIconVal != 0) { + parsingPackage.setIcon(roundIconVal) + .setNonLocalizedLabel(null); + } else { + int iconVal = sa.getResourceId(iconRes, 0); + if (iconVal != 0) { + parsingPackage.setIcon(iconVal) + .setNonLocalizedLabel(null); + } + } + + int logoVal = sa.getResourceId(logoRes, 0); + if (logoVal != 0) { + parsingPackage.setLogo(logoVal); + } + + int bannerVal = sa.getResourceId(bannerRes, 0); + if (bannerVal != 0) { + parsingPackage.setBanner(bannerVal); + } + + TypedValue v = sa.peekValue(labelRes); + if (v != null) { + parsingPackage.setLabelRes(v.resourceId); + if (v.resourceId == 0) { + parsingPackage.setNonLocalizedLabel(v.coerceToString()); + } + } + + return parseInput.success(parsingPackage); + } + + private static ParseResult parsePermissionGroup( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws XmlPullParserException, IOException { + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + + ComponentParseUtils.ParsedPermissionGroup parsedPermissionGroup = + ComponentParseUtils.parsePermissionGroup(parsingPackage, + res, parser, outError); + + if (parsedPermissionGroup == null || outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addPermissionGroup(parsedPermissionGroup); + + return parseInput.success(parsingPackage); + } + + private static ParseResult parsePermission( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws XmlPullParserException, IOException { + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + + ComponentParseUtils.ParsedPermission parsedPermission = + ComponentParseUtils.parsePermission(parsingPackage, + res, parser, outError); + + if (parsedPermission == null || outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addPermission(parsedPermission); + + return parseInput.success(parsingPackage); + } + + private static ParseResult parsePermissionTree( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws XmlPullParserException, IOException { + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + + ComponentParseUtils.ParsedPermission parsedPermission = + ComponentParseUtils.parsePermissionTree(parsingPackage, + res, parser, outError); + + if (parsedPermission == null || outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addPermission(parsedPermission); + + return parseInput.success(parsingPackage); + } + + private static ParseResult parseUsesPermission( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + PackageParser.Callback callback + ) + throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUsesPermission); + + // Note: don't allow this value to be a reference to a resource + // that may change. + String name = sa.getNonResourceString( + R.styleable.AndroidManifestUsesPermission_name); + + int maxSdkVersion = 0; + TypedValue val = sa.peekValue( + R.styleable.AndroidManifestUsesPermission_maxSdkVersion); + if (val != null) { + if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) { + maxSdkVersion = val.data; + } + } + + final String requiredFeature = sa.getNonConfigurationString( + R.styleable.AndroidManifestUsesPermission_requiredFeature, 0); + + final String requiredNotfeature = sa.getNonConfigurationString( + R.styleable.AndroidManifestUsesPermission_requiredNotFeature, + 0); + + sa.recycle(); + + XmlUtils.skipCurrentTag(parser); + + // Can only succeed from here on out + ParseResult success = parseInput.success(parsingPackage); + + if (name == null) { + return success; + } + + if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) { + return success; + } + + // Only allow requesting this permission if the platform supports the given feature. + if (requiredFeature != null && callback != null && !callback.hasFeature(requiredFeature)) { + return success; + } + + // Only allow requesting this permission if the platform doesn't support the given feature. + if (requiredNotfeature != null && callback != null + && callback.hasFeature(requiredNotfeature)) { + return success; + } + + if (!parsingPackage.getRequestedPermissions().contains(name)) { + parsingPackage.addRequestedPermission(name.intern()); + } else { + Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: " + + name + " in package: " + parsingPackage.getPackageName() + " at: " + + parser.getPositionDescription()); + } + + return success; + } + + private static boolean parseUsesConfiguration( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + ConfigurationInfo cPref = new ConfigurationInfo(); + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUsesConfiguration); + cPref.reqTouchScreen = sa.getInt( + R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, + Configuration.TOUCHSCREEN_UNDEFINED); + cPref.reqKeyboardType = sa.getInt( + R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, + Configuration.KEYBOARD_UNDEFINED); + if (sa.getBoolean( + R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, + false)) { + cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; + } + cPref.reqNavigation = sa.getInt( + R.styleable.AndroidManifestUsesConfiguration_reqNavigation, + Configuration.NAVIGATION_UNDEFINED); + if (sa.getBoolean( + R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, + false)) { + cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; + } + sa.recycle(); + parsingPackage.addConfigPreference(cPref); + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static boolean parseUsesFeature( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + FeatureInfo fi = parseFeatureInfo(res, parser); + parsingPackage.addReqFeature(fi); + + if (fi.name == null) { + ConfigurationInfo cPref = new ConfigurationInfo(); + cPref.reqGlEsVersion = fi.reqGlEsVersion; + parsingPackage.addConfigPreference(cPref); + } + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static FeatureInfo parseFeatureInfo(Resources res, AttributeSet attrs) { + FeatureInfo fi = new FeatureInfo(); + TypedArray sa = res.obtainAttributes(attrs, + R.styleable.AndroidManifestUsesFeature); + // Note: don't allow this value to be a reference to a resource + // that may change. + fi.name = sa.getNonResourceString(R.styleable.AndroidManifestUsesFeature_name); + fi.version = sa.getInt(R.styleable.AndroidManifestUsesFeature_version, 0); + if (fi.name == null) { + fi.reqGlEsVersion = sa.getInt(R.styleable.AndroidManifestUsesFeature_glEsVersion, + FeatureInfo.GL_ES_VERSION_UNDEFINED); + } + if (sa.getBoolean(R.styleable.AndroidManifestUsesFeature_required, true)) { + fi.flags |= FeatureInfo.FLAG_REQUIRED; + } + sa.recycle(); + return fi; + } + + private static boolean parseFeatureGroup( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + FeatureGroupInfo group = new FeatureGroupInfo(); + ArrayList<FeatureInfo> features = null; + final int innerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + final String innerTagName = parser.getName(); + if (innerTagName.equals("uses-feature")) { + FeatureInfo featureInfo = parseFeatureInfo(res, parser); + // FeatureGroups are stricter and mandate that + // any <uses-feature> declared are mandatory. + featureInfo.flags |= FeatureInfo.FLAG_REQUIRED; + features = ArrayUtils.add(features, featureInfo); + } else { + Slog.w(TAG, + "Unknown element under <feature-group>: " + innerTagName + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } + XmlUtils.skipCurrentTag(parser); + } + + if (features != null) { + group.features = new FeatureInfo[features.size()]; + group.features = features.toArray(group.features); + } + + parsingPackage.addFeatureGroup(group); + return true; + } + + private static ParseResult parseUsesSdk( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + if (PackageParser.SDK_VERSION > 0) { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUsesSdk); + + int minVers = 1; + String minCode = null; + int targetVers = 0; + String targetCode = null; + + TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion); + if (val != null) { + if (val.type == TypedValue.TYPE_STRING && val.string != null) { + minCode = val.string.toString(); + } else { + // If it's not a string, it's an integer. + minVers = val.data; + } + } + + val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_targetSdkVersion); + if (val != null) { + if (val.type == TypedValue.TYPE_STRING && val.string != null) { + targetCode = val.string.toString(); + if (minCode == null) { + minCode = targetCode; + } + } else { + // If it's not a string, it's an integer. + targetVers = val.data; + } + } else { + targetVers = minVers; + targetCode = minCode; + } + + sa.recycle(); + + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, + minCode, + PackageParser.SDK_VERSION, PackageParser.SDK_CODENAMES, outError); + if (minSdkVersion < 0) { + return parseInput.error( + PackageManager.INSTALL_FAILED_OLDER_SDK + ); + } + + final int targetSdkVersion = PackageParser.computeTargetSdkVersion( + targetVers, + targetCode, PackageParser.SDK_CODENAMES, outError); + if (targetSdkVersion < 0) { + return parseInput.error( + PackageManager.INSTALL_FAILED_OLDER_SDK + ); + } + + parsingPackage.setMinSdkVersion(minSdkVersion) + .setTargetSdkVersion(targetSdkVersion); + } + + XmlUtils.skipCurrentTag(parser); + return parseInput.success(parsingPackage); + } + + private static boolean parseRestrictUpdateHash( + int flags, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + if ((flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestRestrictUpdate); + final String hash = sa.getNonConfigurationString( + R.styleable.AndroidManifestRestrictUpdate_hash, + 0); + sa.recycle(); + + if (hash != null) { + final int hashLength = hash.length(); + final byte[] hashBytes = new byte[hashLength / 2]; + for (int i = 0; i < hashLength; i += 2) { + hashBytes[i / 2] = (byte) ((Character.digit(hash.charAt(i), 16) + << 4) + + Character.digit(hash.charAt(i + 1), 16)); + } + parsingPackage.setRestrictUpdateHash(hashBytes); + } else { + parsingPackage.setRestrictUpdateHash(null); + } + } + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static ParseResult parseQueries( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + + final int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + if (parser.getName().equals("intent")) { + String[] outError = new String[1]; + ComponentParseUtils.ParsedQueriesIntentInfo intentInfo = + ComponentParseUtils.parsedParsedQueriesIntentInfo( + parsingPackage, res, parser, outError + ); + if (intentInfo == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + Uri data = null; + String dataType = null; + String host = ""; + final int numActions = intentInfo.countActions(); + final int numSchemes = intentInfo.countDataSchemes(); + final int numTypes = intentInfo.countDataTypes(); + final int numHosts = intentInfo.getHosts().length; + if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) { + outError[0] = "intent tags must contain either an action or data."; + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + if (numActions > 1) { + outError[0] = "intent tag may have at most one action."; + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + if (numTypes > 1) { + outError[0] = "intent tag may have at most one data type."; + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + if (numSchemes > 1) { + outError[0] = "intent tag may have at most one data scheme."; + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + if (numHosts > 1) { + outError[0] = "intent tag may have at most one data host."; + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + Intent intent = new Intent(); + for (int i = 0, max = intentInfo.countCategories(); i < max; i++) { + intent.addCategory(intentInfo.getCategory(i)); + } + if (numHosts == 1) { + host = intentInfo.getHosts()[0]; + } + if (numSchemes == 1) { + data = new Uri.Builder() + .scheme(intentInfo.getDataScheme(0)) + .authority(host) + .build(); + } + if (numTypes == 1) { + dataType = intentInfo.getDataType(0); + } + intent.setDataAndType(data, dataType); + if (numActions == 1) { + intent.setAction(intentInfo.getAction(0)); + } + parsingPackage.addQueriesIntent(intent); + } else if (parser.getName().equals("package")) { + final TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestQueriesPackage); + final String packageName = + sa.getString(R.styleable.AndroidManifestQueriesPackage_name); + if (TextUtils.isEmpty(packageName)) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Package name is missing from package tag." + ); + } + parsingPackage.addQueriesPackage(packageName.intern()); + } + } + return parseInput.success(parsingPackage); + } + + /** + * Parse the {@code application} XML tree at the current parse location in a + * <em>base APK</em> manifest. + * <p> + * When adding new features, carefully consider if they should also be + * supported by split APKs. + * + * @hide + */ + public static ParseResult parseBaseApplication( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + int flags + ) throws XmlPullParserException, IOException { + final String pkgName = parsingPackage.getPackageName(); + + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + TypedArray sa = null; + + try { + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestApplication); + + + parsingPackage + .setIconRes( + sa.getResourceId(R.styleable.AndroidManifestApplication_icon, 0)) + .setRoundIconRes( + sa.getResourceId(R.styleable.AndroidManifestApplication_roundIcon, 0)); + + ParseResult result = parsePackageItemInfo( + parseInput, + parsingPackage, + "<application>", + sa, false /*nameRequired*/, + R.styleable.AndroidManifestApplication_name, + R.styleable.AndroidManifestApplication_label, + R.styleable.AndroidManifestApplication_icon, + R.styleable.AndroidManifestApplication_roundIcon, + R.styleable.AndroidManifestApplication_logo, + R.styleable.AndroidManifestApplication_banner + ); + if (!result.isSuccess()) { + return result; + } + + String name = parsingPackage.getName(); + if (name != null) { + parsingPackage.setClassName(name); + } + + String manageSpaceActivity = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_manageSpaceActivity, + Configuration.NATIVE_CONFIG_VERSION); + if (manageSpaceActivity != null) { + String manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity); + + if (manageSpaceActivityName == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Empty class name in package " + pkgName + ); + } + + parsingPackage.setManageSpaceActivityName(manageSpaceActivityName); + } + + boolean allowBackup = sa.getBoolean( + R.styleable.AndroidManifestApplication_allowBackup, true); + parsingPackage.setAllowBackup(allowBackup); + + if (allowBackup) { + // backupAgent, killAfterRestore, fullBackupContent, backupInForeground, + // and restoreAnyVersion are only relevant if backup is possible for the + // given application. + String backupAgent = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_backupAgent, + Configuration.NATIVE_CONFIG_VERSION); + if (backupAgent != null) { + String backupAgentName = buildClassName(pkgName, backupAgent); + if (backupAgentName == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Empty class name in package " + pkgName + ); + } + + if (PackageParser.DEBUG_BACKUP) { + Slog.v(TAG, "android:backupAgent = " + backupAgentName + + " from " + pkgName + "+" + backupAgent); + } + + parsingPackage.setBackupAgentName(backupAgentName); + + parsingPackage.setKillAfterRestore(sa.getBoolean( + R.styleable.AndroidManifestApplication_killAfterRestore, true)); + + parsingPackage.setRestoreAnyVersion(sa.getBoolean( + R.styleable.AndroidManifestApplication_restoreAnyVersion, false)); + + parsingPackage.setFullBackupOnly(sa.getBoolean( + R.styleable.AndroidManifestApplication_fullBackupOnly, false)); + + parsingPackage.setBackupInForeground(sa.getBoolean( + R.styleable.AndroidManifestApplication_backupInForeground, + false)); + } + + TypedValue v = sa.peekValue( + R.styleable.AndroidManifestApplication_fullBackupContent); + int fullBackupContent = 0; + + if (v != null) { + fullBackupContent = v.resourceId; + + if (v.resourceId == 0) { + if (PackageParser.DEBUG_BACKUP) { + Slog.v(TAG, "fullBackupContent specified as boolean=" + + (v.data == 0 ? "false" : "true")); + } + // "false" => -1, "true" => 0 + fullBackupContent = v.data == 0 ? -1 : 0; + } + + parsingPackage.setFullBackupContent(fullBackupContent); + } + if (PackageParser.DEBUG_BACKUP) { + Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName); + } + } + + parsingPackage + .setTheme( + sa.getResourceId(R.styleable.AndroidManifestApplication_theme, 0)) + .setDescriptionRes( + sa.getResourceId(R.styleable.AndroidManifestApplication_description, + 0)); + + if (sa.getBoolean( + R.styleable.AndroidManifestApplication_persistent, + false)) { + // Check if persistence is based on a feature being present + final String requiredFeature = sa.getNonResourceString(R.styleable + .AndroidManifestApplication_persistentWhenFeatureAvailable); + parsingPackage.setPersistent(requiredFeature == null + || callback.hasFeature(requiredFeature)); + } + + boolean requiredForAllUsers = sa.getBoolean( + R.styleable.AndroidManifestApplication_requiredForAllUsers, + false); + parsingPackage.setRequiredForAllUsers(requiredForAllUsers); + + String restrictedAccountType = sa.getString(R.styleable + .AndroidManifestApplication_restrictedAccountType); + if (restrictedAccountType != null && restrictedAccountType.length() > 0) { + parsingPackage.setRestrictedAccountType(restrictedAccountType); + } + + String requiredAccountType = sa.getString(R.styleable + .AndroidManifestApplication_requiredAccountType); + if (requiredAccountType != null && requiredAccountType.length() > 0) { + parsingPackage.setRequiredAccountType(requiredAccountType); + } + + parsingPackage.setForceQueryable( + sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false) + ); + + boolean debuggable = sa.getBoolean( + R.styleable.AndroidManifestApplication_debuggable, + false + ); + + parsingPackage.setDebuggable(debuggable); + + if (debuggable) { + // Debuggable implies profileable + parsingPackage.setProfileableByShell(true); + } + + parsingPackage.setVmSafeMode(sa.getBoolean( + R.styleable.AndroidManifestApplication_vmSafeMode, false)); + + boolean baseHardwareAccelerated = sa.getBoolean( + R.styleable.AndroidManifestApplication_hardwareAccelerated, + parsingPackage.getTargetSdkVersion() + >= Build.VERSION_CODES.ICE_CREAM_SANDWICH); + parsingPackage.setBaseHardwareAccelerated(baseHardwareAccelerated); + + parsingPackage.setHasCode(sa.getBoolean( + R.styleable.AndroidManifestApplication_hasCode, true)); + + parsingPackage.setAllowTaskReparenting(sa.getBoolean( + R.styleable.AndroidManifestApplication_allowTaskReparenting, false)); + + parsingPackage.setAllowClearUserData(sa.getBoolean( + R.styleable.AndroidManifestApplication_allowClearUserData, true)); + + parsingPackage.setTestOnly(sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestApplication_testOnly, + false)); + + parsingPackage.setLargeHeap(sa.getBoolean( + R.styleable.AndroidManifestApplication_largeHeap, false)); + + parsingPackage.setUsesCleartextTraffic(sa.getBoolean( + R.styleable.AndroidManifestApplication_usesCleartextTraffic, + parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.P)); + + parsingPackage.setSupportsRtl(sa.getBoolean( + R.styleable.AndroidManifestApplication_supportsRtl, + false /* default is no RTL support*/)); + + parsingPackage.setMultiArch(sa.getBoolean( + R.styleable.AndroidManifestApplication_multiArch, false)); + + parsingPackage.setExtractNativeLibs(sa.getBoolean( + R.styleable.AndroidManifestApplication_extractNativeLibs, true)); + + parsingPackage.setUseEmbeddedDex(sa.getBoolean( + R.styleable.AndroidManifestApplication_useEmbeddedDex, false)); + + parsingPackage.setDefaultToDeviceProtectedStorage(sa.getBoolean( + R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, + false)); + + parsingPackage.setDirectBootAware(sa.getBoolean( + R.styleable.AndroidManifestApplication_directBootAware, false)); + + if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) { + parsingPackage.setActivitiesResizeModeResizeable(sa.getBoolean( + R.styleable.AndroidManifestApplication_resizeableActivity, true)); + } else { + parsingPackage.setActivitiesResizeModeResizeableViaSdkVersion( + parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.N); + } + + parsingPackage.setAllowClearUserDataOnFailedRestore(sa.getBoolean( + R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, + true)); + + + parsingPackage.setAllowAudioPlaybackCapture(sa.getBoolean( + R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, + parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q)); + + parsingPackage.setRequestLegacyExternalStorage(sa.getBoolean( + R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, + parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q)); + + parsingPackage + .setMaxAspectRatio( + sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0)) + .setMinAspectRatio( + sa.getFloat(R.styleable.AndroidManifestApplication_minAspectRatio, 0)) + .setNetworkSecurityConfigRes(sa.getResourceId( + R.styleable.AndroidManifestApplication_networkSecurityConfig, 0)) + .setCategory(sa.getInt(R.styleable.AndroidManifestApplication_appCategory, + ApplicationInfo.CATEGORY_UNDEFINED)); + + String str; + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_permission, 0); + parsingPackage.setPermission((str != null && str.length() > 0) ? str.intern() : null); + + if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_taskAffinity, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + str = sa.getNonResourceString( + R.styleable.AndroidManifestApplication_taskAffinity); + } + String packageName = parsingPackage.getPackageName(); + String taskAffinity = PackageParser.buildTaskAffinityName(packageName, + packageName, + str, outError); + + if (outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.setTaskAffinity(taskAffinity); + String factory = sa.getNonResourceString( + R.styleable.AndroidManifestApplication_appComponentFactory); + if (factory != null) { + String appComponentFactory = buildClassName(packageName, factory); + if (appComponentFactory == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Empty class name in package " + pkgName + ); + } + + parsingPackage.setAppComponentFactory(appComponentFactory); + } + + parsingPackage.setUsesNonSdkApi(sa.getBoolean( + R.styleable.AndroidManifestApplication_usesNonSdkApi, false)); + + parsingPackage.setHasFragileUserData(sa.getBoolean( + R.styleable.AndroidManifestApplication_hasFragileUserData, false)); + + CharSequence pname; + if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { + pname = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_process, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + pname = sa.getNonResourceString( + R.styleable.AndroidManifestApplication_process); + } + String processName = PackageParser.buildProcessName(packageName, null, pname, flags, + separateProcesses, outError); + + if (outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage + .setProcessName(processName) + .setEnabled( + sa.getBoolean(R.styleable.AndroidManifestApplication_enabled, + true)); + + parsingPackage.setIsGame(sa.getBoolean( + R.styleable.AndroidManifestApplication_isGame, false)); + + boolean cantSaveState = sa.getBoolean( + R.styleable.AndroidManifestApplication_cantSaveState, false); + parsingPackage.setCantSaveState(cantSaveState); + if (cantSaveState) { + // A heavy-weight application can not be in a custom process. + // We can do direct compare because we intern all strings. + if (processName != null && !processName.equals(packageName)) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "cantSaveState applications can not use custom processes" + ); + } + } + + String classLoaderName = sa.getString( + R.styleable.AndroidManifestApplication_classLoader); + parsingPackage + .setUiOptions(sa.getInt(R.styleable.AndroidManifestApplication_uiOptions, 0)) + .setClassLoaderName(classLoaderName) + .setZygotePreloadName( + sa.getString(R.styleable.AndroidManifestApplication_zygotePreloadName)); + + if (classLoaderName != null + && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Invalid class loader name: " + classLoaderName + ); + } + } finally { + if (sa != null) { + sa.recycle(); + } + } + + final int innerDepth = parser.getDepth(); + int type; + boolean hasActivityOrder = false; + boolean hasReceiverOrder = false; + boolean hasServiceOrder = false; + + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + switch (tagName) { + case "activity": + ComponentParseUtils.ParsedActivity activity = + ComponentParseUtils.parseActivity(separateProcesses, + parsingPackage, + res, parser, flags, + outError, false, + parsingPackage.isBaseHardwareAccelerated()); + if (activity == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + hasActivityOrder |= (activity.order != 0); + parsingPackage.addActivity(activity); + break; + case "receiver": + activity = ComponentParseUtils.parseActivity(separateProcesses, + parsingPackage, + res, parser, + flags, outError, + true, false); + if (activity == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + hasReceiverOrder |= (activity.order != 0); + parsingPackage.addReceiver(activity); + break; + case "service": + ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService( + separateProcesses, + parsingPackage, + res, parser, flags, + outError); + if (s == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + hasServiceOrder |= (s.order != 0); + parsingPackage.addService(s); + break; + case "provider": + ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider( + separateProcesses, + parsingPackage, + res, parser, flags, + outError + ); + if (p == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addProvider(p); + break; + case "activity-alias": + activity = ComponentParseUtils.parseActivityAlias( + parsingPackage, + res, + parser, + outError + ); + if (activity == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + hasActivityOrder |= (activity.order != 0); + parsingPackage.addActivity(activity); + break; + case "meta-data": + // note: application meta-data is stored off to the side, so it can + // remain null in the primary copy (we like to avoid extra copies because + // it can be large) + Bundle appMetaData = parseMetaData(parsingPackage, res, parser, + parsingPackage.getAppMetaData(), + outError); + if (appMetaData == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.setAppMetaData(appMetaData); + break; + case "static-library": + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestStaticLibrary); + + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestStaticLibrary_name); + final int version = sa.getInt( + R.styleable.AndroidManifestStaticLibrary_version, -1); + final int versionMajor = sa.getInt( + R.styleable.AndroidManifestStaticLibrary_versionMajor, + 0); + + sa.recycle(); + + // Since the app canot run without a static lib - fail if malformed + if (lname == null || version < 0) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad static-library declaration name: " + lname + + " version: " + version + ); + } + + if (parsingPackage.getSharedUserId() != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, + "sharedUserId not allowed in static shared library" + ); + } + + if (parsingPackage.getStaticSharedLibName() != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Multiple static-shared libs for package " + pkgName + ); + } + + parsingPackage.setStaticSharedLibName(lname.intern()); + if (version >= 0) { + parsingPackage.setStaticSharedLibVersion( + PackageInfo.composeLongVersionCode(versionMajor, version)); + } else { + parsingPackage.setStaticSharedLibVersion(version); + } + parsingPackage.setStaticSharedLibrary(true); + + XmlUtils.skipCurrentTag(parser); + + break; + case "library": + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestLibrary); + + // Note: don't allow this value to be a reference to a resource + // that may change. + lname = sa.getNonResourceString( + R.styleable.AndroidManifestLibrary_name); + + sa.recycle(); + + if (lname != null) { + lname = lname.intern(); + if (!ArrayUtils.contains(parsingPackage.getLibraryNames(), lname)) { + parsingPackage.addLibraryName(lname); + } + } + + XmlUtils.skipCurrentTag(parser); + + break; + case "uses-static-library": + ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage, + res, parser); + if (!parseResult.isSuccess()) { + return parseResult; + } + break; + case "uses-library": + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUsesLibrary); + + // Note: don't allow this value to be a reference to a resource + // that may change. + lname = sa.getNonResourceString( + R.styleable.AndroidManifestUsesLibrary_name); + boolean req = sa.getBoolean( + R.styleable.AndroidManifestUsesLibrary_required, + true); + + sa.recycle(); + + if (lname != null) { + lname = lname.intern(); + if (req) { + parsingPackage.addUsesLibrary(lname); + } else { + parsingPackage.addUsesOptionalLibrary(lname); + } + } + + XmlUtils.skipCurrentTag(parser); + + break; + case "uses-package": + // Dependencies for app installers; we don't currently try to + // enforce this. + XmlUtils.skipCurrentTag(parser); + break; + case "profileable": + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestProfileable); + if (sa.getBoolean( + R.styleable.AndroidManifestProfileable_shell, false)) { + parsingPackage.setProfileableByShell(true); + } + XmlUtils.skipCurrentTag(parser); + + default: + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <application>: " + tagName + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad element under <application>: " + tagName + ); + } + } + } + + if (TextUtils.isEmpty(parsingPackage.getStaticSharedLibName())) { + // Add a hidden app detail activity to normal apps which forwards user to App Details + // page. + ComponentParseUtils.ParsedActivity a = generateAppDetailsHiddenActivity( + parsingPackage, + outError + ); + // Ignore errors here + parsingPackage.addActivity(a); + } + + if (hasActivityOrder) { + parsingPackage.sortActivities(); + } + if (hasReceiverOrder) { + parsingPackage.sortReceivers(); + } + if (hasServiceOrder) { + parsingPackage.sortServices(); + } + // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after + // every activity info has had a chance to set it from its attributes. + setMaxAspectRatio(parsingPackage); + setMinAspectRatio(parsingPackage, callback); + + parsingPackage.setHasDomainUrls(hasDomainURLs(parsingPackage)); + + return parseInput.success(parsingPackage); + } + + private static ParseResult parseUsesStaticLibrary( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUsesStaticLibrary); + + // Note: don't allow this value to be a reference to a resource that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestUsesLibrary_name); + final int version = sa.getInt( + R.styleable.AndroidManifestUsesStaticLibrary_version, -1); + String certSha256Digest = sa.getNonResourceString(com.android.internal.R.styleable + .AndroidManifestUsesStaticLibrary_certDigest); + sa.recycle(); + + // Since an APK providing a static shared lib can only provide the lib - fail if malformed + if (lname == null || version < 0 || certSha256Digest == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad uses-static-library declaration name: " + lname + " version: " + + version + " certDigest" + certSha256Digest + ); + } + + // Can depend only on one version of the same library + List<String> usesStaticLibraries = parsingPackage.getUsesStaticLibraries(); + if (usesStaticLibraries != null && usesStaticLibraries.contains(lname)) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Depending on multiple versions of static library " + lname + ); + } + + lname = lname.intern(); + // We allow ":" delimiters in the SHA declaration as this is the format + // emitted by the certtool making it easy for developers to copy/paste. + certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); + + // Fot apps targeting O-MR1 we require explicit enumeration of all certs. + String[] additionalCertSha256Digests = EmptyArray.STRING; + if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.O_MR1) { + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + additionalCertSha256Digests = parseAdditionalCertificates(res, parser, outError); + if (additionalCertSha256Digests == null || outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + } else { + XmlUtils.skipCurrentTag(parser); + } + + final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1]; + certSha256Digests[0] = certSha256Digest; + System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests, + 1, additionalCertSha256Digests.length); + + parsingPackage.addUsesStaticLibrary(lname) + .addUsesStaticLibraryVersion(version) + .addUsesStaticLibraryCertDigests(certSha256Digests); + + return parseInput.success(parsingPackage); + } + + private static String[] parseAdditionalCertificates( + Resources resources, + XmlResourceParser parser, + String[] outError + ) throws XmlPullParserException, IOException { + String[] certSha256Digests = EmptyArray.STRING; + + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + final String nodeName = parser.getName(); + if (nodeName.equals("additional-certificate")) { + final TypedArray sa = resources.obtainAttributes(parser, com.android.internal. + R.styleable.AndroidManifestAdditionalCertificate); + String certSha256Digest = sa.getNonResourceString(com.android.internal. + R.styleable.AndroidManifestAdditionalCertificate_certDigest); + sa.recycle(); + + if (TextUtils.isEmpty(certSha256Digest)) { + outError[0] = "Bad additional-certificate declaration with empty" + + " certDigest:" + certSha256Digest; + XmlUtils.skipCurrentTag(parser); + sa.recycle(); + return null; + } + + // We allow ":" delimiters in the SHA declaration as this is the format + // emitted by the certtool making it easy for developers to copy/paste. + certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); + certSha256Digests = ArrayUtils.appendElement(String.class, + certSha256Digests, certSha256Digest); + } else { + XmlUtils.skipCurrentTag(parser); + } + } + + return certSha256Digests; + } + + /** + * Generate activity object that forwards user to App Details page automatically. + * This activity should be invisible to user and user should not know or see it. + * + * @hide + */ + @NonNull + private static ComponentParseUtils.ParsedActivity generateAppDetailsHiddenActivity( + ParsingPackage parsingPackage, + String[] outError + ) { + String packageName = parsingPackage.getPackageName(); + String processName = parsingPackage.getProcessName(); + boolean hardwareAccelerated = parsingPackage.isBaseHardwareAccelerated(); + int uiOptions = parsingPackage.getUiOptions(); + + // Build custom App Details activity info instead of parsing it from xml + ComponentParseUtils.ParsedActivity activity = new ComponentParseUtils.ParsedActivity(); + activity.setPackageName(packageName); + + activity.theme = android.R.style.Theme_NoDisplay; + activity.exported = true; + activity.className = PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME; + activity.setProcessName(processName, processName); + activity.uiOptions = uiOptions; + activity.taskAffinity = PackageParser.buildTaskAffinityName(packageName, + packageName, + ":app_details", outError); + activity.enabled = true; + activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; + activity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE; + activity.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic(); + activity.configChanges = PackageParser.getActivityConfigChanges(0, 0); + activity.softInputMode = 0; + activity.persistableMode = ActivityInfo.PERSIST_NEVER; + activity.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED; + activity.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; + activity.lockTaskLaunchMode = 0; + activity.directBootAware = false; + activity.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED; + activity.colorMode = ActivityInfo.COLOR_MODE_DEFAULT; + if (hardwareAccelerated) { + activity.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; + } + + return activity; + } + + /** + * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI + */ + private static boolean hasDomainURLs( + ParsingPackage parsingPackage) { + final List<ComponentParseUtils.ParsedActivity> activities = parsingPackage.getActivities(); + final int countActivities = activities.size(); + for (int n = 0; n < countActivities; n++) { + ComponentParseUtils.ParsedActivity activity = activities.get(n); + List<ComponentParseUtils.ParsedActivityIntentInfo> filters = activity.intents; + if (filters == null) continue; + final int countFilters = filters.size(); + for (int m = 0; m < countFilters; m++) { + ComponentParseUtils.ParsedActivityIntentInfo aii = filters.get(m); + if (!aii.hasAction(Intent.ACTION_VIEW)) continue; + if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue; + if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) || + aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) { + return true; + } + } + } + return false; + } + + /** + * Sets the max aspect ratio of every child activity that doesn't already have an aspect + * ratio set. + */ + private static void setMaxAspectRatio( + ParsingPackage parsingPackage) { + // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater. + // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD. + float maxAspectRatio = parsingPackage.getTargetSdkVersion() < O + ? PackageParser.DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0; + + float packageMaxAspectRatio = parsingPackage.getMaxAspectRatio(); + if (packageMaxAspectRatio != 0) { + // Use the application max aspect ration as default if set. + maxAspectRatio = packageMaxAspectRatio; + } else { + Bundle appMetaData = parsingPackage.getAppMetaData(); + if (appMetaData != null && appMetaData.containsKey( + PackageParser.METADATA_MAX_ASPECT_RATIO)) { + maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO, + maxAspectRatio); + } + } + + if (parsingPackage.getActivities() != null) { + for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) { + // If the max aspect ratio for the activity has already been set, skip. + if (activity.hasMaxAspectRatio()) { + continue; + } + + // By default we prefer to use a values defined on the activity directly than values + // defined on the application. We do not check the styled attributes on the activity + // as it would have already been set when we processed the activity. We wait to + // process the meta data here since this method is called at the end of processing + // the application and all meta data is guaranteed. + final float activityAspectRatio = activity.metaData != null + ? activity.metaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO, + maxAspectRatio) + : maxAspectRatio; + + activity.setMaxAspectRatio(activity.resizeMode, activityAspectRatio); + } + } + } + + /** + * Sets the min aspect ratio of every child activity that doesn't already have an aspect + * ratio set. + */ + private static void setMinAspectRatio( + ParsingPackage parsingPackage, + PackageParser.Callback callback + ) { + final float minAspectRatio; + float packageMinAspectRatio = parsingPackage.getMinAspectRatio(); + if (packageMinAspectRatio != 0) { + // Use the application max aspect ration as default if set. + minAspectRatio = packageMinAspectRatio; + } else { + // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater. + // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD, + // except for watches which always supported 1:1. + minAspectRatio = parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q + ? 0 + : (callback != null && callback.hasFeature(FEATURE_WATCH)) + ? PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH + : PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO; + } + + if (parsingPackage.getActivities() != null) { + for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) { + if (activity.hasMinAspectRatio()) { + continue; + } + activity.setMinAspectRatio(activity.resizeMode, minAspectRatio); + } + } + } + + private static ParseResult parseOverlay( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay); + String target = sa.getString( + R.styleable.AndroidManifestResourceOverlay_targetPackage); + String targetName = sa.getString( + R.styleable.AndroidManifestResourceOverlay_targetName); + String category = sa.getString( + R.styleable.AndroidManifestResourceOverlay_category); + int priority = sa.getInt(R.styleable.AndroidManifestResourceOverlay_priority, + 0); + boolean isStatic = sa.getBoolean( + R.styleable.AndroidManifestResourceOverlay_isStatic, false); + + if (target == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "<overlay> does not specify a target package" + ); + } + + if (priority < 0 || priority > 9999) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "<overlay> priority must be between 0 and 9999" + ); + } + + // check to see if overlay should be excluded based on system property condition + String propName = sa.getString( + R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName); + String propValue = sa.getString( + R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue); + if (!checkOverlayRequiredSystemProperty(propName, propValue)) { + Slog.i(TAG, "Skipping target and overlay pair " + target + " and " + + parsingPackage.getBaseCodePath() + + ": overlay ignored due to required system property: " + + propName + " with value: " + propValue); + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Skipping target and overlay pair " + target + " and " + + parsingPackage.getBaseCodePath() + + ": overlay ignored due to required system property: " + + propName + " with value: " + propValue + ); + } + + parsingPackage + .setIsOverlay(true) + .setOverlayTarget(target) + .setOverlayTargetName(targetName) + .setOverlayCategory(category) + .setOverlayPriority(priority) + .setOverlayIsStatic(isStatic); + + sa.recycle(); + + XmlUtils.skipCurrentTag(parser); + return parseInput.success(parsingPackage); + } + + private static boolean parseProtectedBroadcast( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestProtectedBroadcast); + + // Note: don't allow this value to be a reference to a resource + // that may change. + String name = sa.getNonResourceString(R.styleable.AndroidManifestProtectedBroadcast_name); + + sa.recycle(); + + if (name != null) { + parsingPackage.addProtectedBroadcast(name); + } + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static boolean parseSupportScreens( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestSupportsScreens); + + int requiresSmallestWidthDp = sa.getInteger( + R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, + 0); + int compatibleWidthLimitDp = sa.getInteger( + R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, + 0); + int largestWidthLimitDp = sa.getInteger( + R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, + 0); + + // This is a trick to get a boolean and still able to detect + // if a value was actually set. + parsingPackage + .setSupportsSmallScreens( + sa.getInteger(R.styleable.AndroidManifestSupportsScreens_smallScreens, 1)) + .setSupportsNormalScreens( + sa.getInteger(R.styleable.AndroidManifestSupportsScreens_normalScreens, 1)) + .setSupportsLargeScreens( + sa.getInteger(R.styleable.AndroidManifestSupportsScreens_largeScreens, 1)) + .setSupportsXLargeScreens( + sa.getInteger(R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1)) + .setResizeable( + sa.getInteger(R.styleable.AndroidManifestSupportsScreens_resizeable, 1)) + .setAnyDensity( + sa.getInteger(R.styleable.AndroidManifestSupportsScreens_anyDensity, 1)) + .setRequiresSmallestWidthDp(requiresSmallestWidthDp) + .setCompatibleWidthLimitDp(compatibleWidthLimitDp) + .setLargestWidthLimitDp(largestWidthLimitDp); + + sa.recycle(); + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static ParseResult parseInstrumentation( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws XmlPullParserException, IOException { + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + + ComponentParseUtils.ParsedInstrumentation parsedInstrumentation = + ComponentParseUtils.parseInstrumentation(parsingPackage, + res, parser, outError); + + if (parsedInstrumentation == null || outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addInstrumentation(parsedInstrumentation); + + return parseInput.success(parsingPackage); + } + + private static boolean parseOriginalPackage( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestOriginalPackage); + + String orig = sa.getNonConfigurationString( + R.styleable.AndroidManifestOriginalPackage_name, + 0); + if (!parsingPackage.getPackageName().equals(orig)) { + if (parsingPackage.getOriginalPackages() == null) { + parsingPackage.setRealPackage(parsingPackage.getPackageName()); + } + parsingPackage.addOriginalPackage(orig); + } + + sa.recycle(); + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static boolean parseAdoptPermissions( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestOriginalPackage); + + String name = sa.getNonConfigurationString( + R.styleable.AndroidManifestOriginalPackage_name, + 0); + + sa.recycle(); + + if (name != null) { + parsingPackage.addAdoptPermission(name); + } + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static void convertNewPermissions( + ParsingPackage packageToParse) { + final int NP = PackageParser.NEW_PERMISSIONS.length; + StringBuilder newPermsMsg = null; + for (int ip = 0; ip < NP; ip++) { + final PackageParser.NewPermissionInfo npi + = PackageParser.NEW_PERMISSIONS[ip]; + if (packageToParse.getTargetSdkVersion() >= npi.sdkVersion) { + break; + } + if (!packageToParse.getRequestedPermissions().contains(npi.name)) { + if (newPermsMsg == null) { + newPermsMsg = new StringBuilder(128); + newPermsMsg.append(packageToParse.getPackageName()); + newPermsMsg.append(": compat added "); + } else { + newPermsMsg.append(' '); + } + newPermsMsg.append(npi.name); + packageToParse.addRequestedPermission(npi.name); + packageToParse.addImplicitPermission(npi.name); + } + } + if (newPermsMsg != null) { + Slog.i(TAG, newPermsMsg.toString()); + } + } + + private static void convertSplitPermissions(ParsingPackage packageToParse) { + List<SplitPermissionInfoParcelable> splitPermissions; + + try { + splitPermissions = ActivityThread.getPermissionManager().getSplitPermissions(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + final int listSize = splitPermissions.size(); + for (int is = 0; is < listSize; is++) { + final SplitPermissionInfoParcelable spi = splitPermissions.get(is); + List<String> requestedPermissions = packageToParse.getRequestedPermissions(); + if (packageToParse.getTargetSdkVersion() >= spi.getTargetSdk() + || !requestedPermissions.contains(spi.getSplitPermission())) { + continue; + } + final List<String> newPerms = spi.getNewPermissions(); + for (int in = 0; in < newPerms.size(); in++) { + final String perm = newPerms.get(in); + if (!requestedPermissions.contains(perm)) { + packageToParse.addRequestedPermission(perm); + packageToParse.addImplicitPermission(perm); + } + } + } + } + + private static boolean checkOverlayRequiredSystemProperty(String propName, String propValue) { + if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) { + if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) { + // malformed condition - incomplete + Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName + + "=" + propValue + "' - require both requiredSystemPropertyName" + + " AND requiredSystemPropertyValue to be specified."); + return false; + } + // no valid condition set - so no exclusion criteria, overlay will be included. + return true; + } + + // check property value - make sure it is both set and equal to expected value + final String currValue = SystemProperties.get(propName); + return (currValue != null && currValue.equals(propValue)); + } + + /** + * This is a pre-density application which will get scaled - instead of being pixel perfect. + * This type of application is not resizable. + * + * @param parsingPackage The package which needs to be marked as unresizable. + */ + private static void adjustPackageToBeUnresizeableAndUnpipable( + ParsingPackage parsingPackage) { + if (parsingPackage.getActivities() != null) { + for (ComponentParseUtils.ParsedActivity a : parsingPackage.getActivities()) { + a.resizeMode = RESIZE_MODE_UNRESIZEABLE; + a.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE; + } + } + } + + private static String validateName(String name, boolean requireSeparator, + boolean requireFilename) { + final int N = name.length(); + boolean hasSep = false; + boolean front = true; + for (int i = 0; i < N; i++) { + final char c = name.charAt(i); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + front = false; + continue; + } + if (!front) { + if ((c >= '0' && c <= '9') || c == '_') { + continue; + } + } + if (c == '.') { + hasSep = true; + front = true; + continue; + } + return "bad character '" + c + "'"; + } + if (requireFilename && !FileUtils.isValidExtFilename(name)) { + return "Invalid filename"; + } + return hasSep || !requireSeparator + ? null : "must have at least one '.' separator"; + } + + public static Bundle parseMetaData( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, Bundle data, String[] outError) + throws XmlPullParserException, IOException { + + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestMetaData); + + if (data == null) { + data = new Bundle(); + } + + String name = sa.getNonConfigurationString( + R.styleable.AndroidManifestMetaData_name, 0); + if (name == null) { + outError[0] = "<meta-data> requires an android:name attribute"; + sa.recycle(); + return null; + } + + name = name.intern(); + + TypedValue v = sa.peekValue( + R.styleable.AndroidManifestMetaData_resource); + if (v != null && v.resourceId != 0) { + //Slog.i(TAG, "Meta data ref " + name + ": " + v); + data.putInt(name, v.resourceId); + } else { + v = sa.peekValue( + R.styleable.AndroidManifestMetaData_value); + //Slog.i(TAG, "Meta data " + name + ": " + v); + if (v != null) { + if (v.type == TypedValue.TYPE_STRING) { + CharSequence cs = v.coerceToString(); + data.putString(name, cs != null ? cs.toString() : null); + } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { + data.putBoolean(name, v.data != 0); + } else if (v.type >= TypedValue.TYPE_FIRST_INT + && v.type <= TypedValue.TYPE_LAST_INT) { + data.putInt(name, v.data); + } else if (v.type == TypedValue.TYPE_FLOAT) { + data.putFloat(name, v.getFloat()); + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, + "<meta-data> only supports string, integer, float, color, " + + "boolean, and resource reference types: " + + parser.getName() + " at " + + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } else { + outError[0] = + "<meta-data> only supports string, integer, float, color, " + + "boolean, and resource reference types"; + data = null; + } + } + } else { + outError[0] = "<meta-data> requires an android:value or android:resource attribute"; + data = null; + } + } + + sa.recycle(); + + XmlUtils.skipCurrentTag(parser); + + return data; + } + + /** + * Collect certificates from all the APKs described in the given package, + * populating {@link AndroidPackageWrite#setSigningDetails(SigningDetails)}. Also asserts that + * all APK contents are signed correctly and consistently. + */ + public static void collectCertificates(AndroidPackage pkg, boolean skipVerify) + throws PackageParserException { + pkg.mutate().setSigningDetails(SigningDetails.UNKNOWN); + + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); + try { + pkg.mutate().setSigningDetails(collectCertificates( + pkg.getBaseCodePath(), + skipVerify, + pkg.isStaticSharedLibrary(), + pkg.getSigningDetails() + )); + + String[] splitCodePaths = pkg.getSplitCodePaths(); + if (!ArrayUtils.isEmpty(splitCodePaths)) { + for (int i = 0; i < splitCodePaths.length; i++) { + pkg.mutate().setSigningDetails(collectCertificates( + splitCodePaths[i], + skipVerify, + pkg.isStaticSharedLibrary(), + pkg.getSigningDetails() + )); + } + } + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + + public static SigningDetails collectCertificates( + String baseCodePath, + boolean skipVerify, + boolean isStaticSharedLibrary, + @NonNull SigningDetails existingSigningDetails + ) throws PackageParserException { + int minSignatureScheme = SigningDetails.SignatureSchemeVersion.JAR; + if (isStaticSharedLibrary) { + // must use v2 signing scheme + minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2; + } + SigningDetails verified; + if (skipVerify) { + // systemDir APKs are already trusted, save time by not verifying + verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification( + baseCodePath, minSignatureScheme); + } else { + verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme); + } + + // Verify that entries are signed consistently with the first pkg + // we encountered. Note that for splits, certificates may have + // already been populated during an earlier parse of a base APK. + if (existingSigningDetails == SigningDetails.UNKNOWN) { + return verified; + } else { + if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) { + throw new PackageParserException( + INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, + baseCodePath + " has mismatched certificates"); + } + + return existingSigningDetails; + } + } + + @Nullable + public static String buildClassName(String pkg, CharSequence clsSeq) { + if (clsSeq == null || clsSeq.length() <= 0) { + return null; + } + String cls = clsSeq.toString(); + char c = cls.charAt(0); + if (c == '.') { + return pkg + cls; + } + if (cls.indexOf('.') < 0) { + StringBuilder b = new StringBuilder(pkg); + b.append('.'); + b.append(cls); + return b.toString(); + } + return cls; + } + + public interface ParseInput { + ParseResult success(ParsingPackage result); + + ParseResult error(int parseError); + + ParseResult error(int parseError, String errorMessage); + } + + public static class ParseResult implements ParseInput { + + private static final boolean DEBUG_FILL_STACK_TRACE = false; + + private ParsingPackage result; + + private int parseError; + private String errorMessage; + + public ParseInput reset() { + this.result = null; + this.parseError = PackageManager.INSTALL_SUCCEEDED; + this.errorMessage = null; + return this; + } + + @Override + public ParseResult success(ParsingPackage result) { + if (parseError != PackageManager.INSTALL_SUCCEEDED || errorMessage != null) { + throw new IllegalStateException("Cannot set to success after set to error"); + } + this.result = result; + return this; + } + + @Override + public ParseResult error(int parseError) { + return error(parseError, null); + } + + @Override + public ParseResult error(int parseError, String errorMessage) { + this.parseError = parseError; + this.errorMessage = errorMessage; + + if (DEBUG_FILL_STACK_TRACE) { + this.errorMessage += Arrays.toString(new Exception().getStackTrace()); + } + + return this; + } + + public ParsingPackage getResultAndNull() { + ParsingPackage result = this.result; + this.result = null; + return result; + } + + public boolean isSuccess() { + return parseError == PackageManager.INSTALL_SUCCEEDED; + } + + public int getParseError() { + return parseError; + } + + public String getErrorMessage() { + return errorMessage; + } + } +} diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java new file mode 100644 index 000000000000..5364313f5760 --- /dev/null +++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java @@ -0,0 +1,3250 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing; + +import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; +import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; + +import android.annotation.CallSuper; +import android.annotation.UnsupportedAppUsage; +import android.app.ActivityTaskManager; +import android.content.ComponentName; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PathPermission; +import android.content.pm.PermissionInfo; +import android.content.pm.ProviderInfo; +import android.content.pm.ServiceInfo; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Build; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.PatternMatcher; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Slog; +import android.util.TypedValue; +import android.view.Gravity; + +import com.android.internal.R; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + +/** + * TODO(b/135203078): Move the inner classes out to separate files. + * TODO(b/135203078): Expose inner classes as immutable through interface methods. + * + * @hide + */ +public class ComponentParseUtils { + + private static final String TAG = ApkParseUtils.TAG; + + // TODO(b/135203078): None of this class's subclasses do anything. Remove in favor of base? + public static class ParsedIntentInfo extends IntentFilter { + + /** + * <p> + * Implementation note: The serialized form for the intent list also contains the name + * of the concrete class that's stored in the list, and assumes that every element of the + * list is of the same type. This is very similar to the original parcelable mechanism. + * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable + * and is public API. It also declares Parcelable related methods as final which means + * we can't extend them. The approach of using composition instead of inheritance leads to + * a large set of cascading changes in the PackageManagerService, which seem undesirable. + * + * <p> + * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up + * to make sure their owner fields are consistent. See {@code fixupOwner}. + */ + public static void writeIntentsList(List<? extends ParsedIntentInfo> list, Parcel out, + int flags) { + if (list == null) { + out.writeInt(-1); + return; + } + + final int size = list.size(); + out.writeInt(size); + + // Don't bother writing the component name if the list is empty. + if (size > 0) { + ParsedIntentInfo info = list.get(0); + out.writeString(info.getClass().getName()); + + for (int i = 0; i < size; i++) { + list.get(i).writeIntentInfoToParcel(out, flags); + } + } + } + + public static <T extends ParsedIntentInfo> ArrayList<T> createIntentsList(Parcel in) { + int size = in.readInt(); + if (size == -1) { + return null; + } + + if (size == 0) { + return new ArrayList<>(0); + } + + String className = in.readString(); + final ArrayList<T> intentsList; + try { + final Class<T> cls = (Class<T>) Class.forName(className); + final Constructor<T> cons = cls.getConstructor(Parcel.class); + + intentsList = new ArrayList<>(size); + for (int i = 0; i < size; ++i) { + intentsList.add(cons.newInstance(in)); + } + } catch (ReflectiveOperationException ree) { + throw new AssertionError("Unable to construct intent list for: " + + className, ree); + } + + return intentsList; + } + + protected String packageName; + protected final String className; + + public boolean hasDefault; + public int labelRes; + public CharSequence nonLocalizedLabel; + public int icon; + + protected List<String> rawDataTypes; + + public void addRawDataType(String dataType) throws MalformedMimeTypeException { + if (rawDataTypes == null) { + rawDataTypes = new ArrayList<>(); + } + + rawDataTypes.add(dataType); + addDataType(dataType); + } + + public ParsedIntentInfo(String packageName, String className) { + this.packageName = packageName; + this.className = className; + } + + public ParsedIntentInfo(Parcel in) { + super(in); + packageName = in.readString(); + className = in.readString(); + hasDefault = (in.readInt() == 1); + labelRes = in.readInt(); + nonLocalizedLabel = in.readCharSequence(); + icon = in.readInt(); + } + + public void writeIntentInfoToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(packageName); + dest.writeString(className); + dest.writeInt(hasDefault ? 1 : 0); + dest.writeInt(labelRes); + dest.writeCharSequence(nonLocalizedLabel); + dest.writeInt(icon); + } + + public String getPackageName() { + return packageName; + } + + public String getClassName() { + return className; + } + } + + public static class ParsedActivityIntentInfo extends ParsedIntentInfo { + + public ParsedActivityIntentInfo(String packageName, String className) { + super(packageName, className); + } + + public ParsedActivityIntentInfo(Parcel in) { + super(in); + } + + public static final Creator<ParsedActivityIntentInfo> CREATOR = + new Creator<ParsedActivityIntentInfo>() { + @Override + public ParsedActivityIntentInfo createFromParcel(Parcel source) { + return new ParsedActivityIntentInfo(source); + } + + @Override + public ParsedActivityIntentInfo[] newArray(int size) { + return new ParsedActivityIntentInfo[size]; + } + }; + } + + public static class ParsedServiceIntentInfo extends ParsedIntentInfo { + + public ParsedServiceIntentInfo(String packageName, String className) { + super(packageName, className); + } + + public ParsedServiceIntentInfo(Parcel in) { + super(in); + } + + public static final Creator<ParsedServiceIntentInfo> CREATOR = + new Creator<ParsedServiceIntentInfo>() { + @Override + public ParsedServiceIntentInfo createFromParcel(Parcel source) { + return new ParsedServiceIntentInfo(source); + } + + @Override + public ParsedServiceIntentInfo[] newArray(int size) { + return new ParsedServiceIntentInfo[size]; + } + }; + } + + public static class ParsedProviderIntentInfo extends ParsedIntentInfo { + + public ParsedProviderIntentInfo(String packageName, String className) { + super(packageName, className); + } + + public ParsedProviderIntentInfo(Parcel in) { + super(in); + } + + public static final Creator<ParsedProviderIntentInfo> CREATOR = + new Creator<ParsedProviderIntentInfo>() { + @Override + public ParsedProviderIntentInfo createFromParcel(Parcel source) { + return new ParsedProviderIntentInfo(source); + } + + @Override + public ParsedProviderIntentInfo[] newArray(int size) { + return new ParsedProviderIntentInfo[size]; + } + }; + } + + public static class ParsedQueriesIntentInfo extends ParsedIntentInfo { + + public ParsedQueriesIntentInfo(String packageName, String className) { + super(packageName, className); + } + + public ParsedQueriesIntentInfo(Parcel in) { + super(in); + } + + public static final Creator<ParsedQueriesIntentInfo> CREATOR = + new Creator<ParsedQueriesIntentInfo>() { + @Override + public ParsedQueriesIntentInfo createFromParcel(Parcel source) { + return new ParsedQueriesIntentInfo(source); + } + + @Override + public ParsedQueriesIntentInfo[] newArray(int size) { + return new ParsedQueriesIntentInfo[size]; + } + }; + } + + public static class ParsedComponent<IntentInfoType extends ParsedIntentInfo> implements + Parcelable { + + // TODO(b/135203078): Replace with "name", as not all usages are an actual class + public String className; + public int icon; + public int labelRes; + public CharSequence nonLocalizedLabel; + public int logo; + public int banner; + + public int descriptionRes; + + // TODO(b/135203078): Make subclass that contains these fields only for the necessary + // subtypes + protected boolean enabled = true; + protected boolean directBootAware; + public int flags; + + private String packageName; + private String splitName; + + // TODO(b/135203078): Make nullable + public List<IntentInfoType> intents = new ArrayList<>(); + + private transient ComponentName componentName; + + protected Bundle metaData; + + public void setSplitName(String splitName) { + this.splitName = splitName; + } + + public String getSplitName() { + return splitName; + } + + @CallSuper + public void setPackageName(String packageName) { + this.packageName = packageName; + this.componentName = null; + } + + void setPackageNameInternal(String packageName) { + this.packageName = packageName; + this.componentName = null; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getPackageName() { + return packageName; + } + + public final boolean isDirectBootAware() { + return directBootAware; + } + + public final boolean isEnabled() { + return enabled; + } + + public final String getName() { + return className; + } + + public final Bundle getMetaData() { + return metaData; + } + + @UnsupportedAppUsage + public ComponentName getComponentName() { + if (componentName != null) { + return componentName; + } + if (className != null) { + componentName = new ComponentName(getPackageName(), + className); + } + return componentName; + } + + public void setFrom(ParsedComponent other) { + this.metaData = other.metaData; + this.className = other.className; + this.icon = other.icon; + this.labelRes = other.labelRes; + this.nonLocalizedLabel = other.nonLocalizedLabel; + this.logo = other.logo; + this.banner = other.banner; + + this.descriptionRes = other.descriptionRes; + + this.enabled = other.enabled; + this.directBootAware = other.directBootAware; + this.flags = other.flags; + + this.setPackageName(other.packageName); + this.setSplitName(other.getSplitName()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.className); + dest.writeInt(this.icon); + dest.writeInt(this.labelRes); + dest.writeCharSequence(this.nonLocalizedLabel); + dest.writeInt(this.logo); + dest.writeInt(this.banner); + dest.writeInt(this.descriptionRes); + dest.writeBoolean(this.enabled); + dest.writeBoolean(this.directBootAware); + dest.writeInt(this.flags); + dest.writeString(this.packageName); + dest.writeString(this.splitName); + ParsedIntentInfo.writeIntentsList(this.intents, dest, flags); + dest.writeBundle(this.metaData); + } + + public ParsedComponent() { + } + + protected ParsedComponent(Parcel in) { + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + this.className = in.readString(); + this.icon = in.readInt(); + this.labelRes = in.readInt(); + this.nonLocalizedLabel = in.readCharSequence(); + this.logo = in.readInt(); + this.banner = in.readInt(); + this.descriptionRes = in.readInt(); + this.enabled = in.readByte() != 0; + this.directBootAware = in.readByte() != 0; + this.flags = in.readInt(); + this.packageName = in.readString(); + this.splitName = in.readString(); + this.intents = ParsedIntentInfo.createIntentsList(in); + this.metaData = in.readBundle(boot); + } + } + + // TODO(b/135203078): Document this. Maybe split out ParsedComponent to be actual components + // that can have their own processes, rather than something like permission which cannot. + public static class ParsedMainComponent<IntentInfoType extends ParsedIntentInfo> extends + ParsedComponent<IntentInfoType> { + + private String processName; + private String permission; + + public void setProcessName(String appProcessName, String processName) { + // TODO(b/135203078): Is this even necessary anymore? + this.processName = TextUtils.safeIntern( + processName == null ? appProcessName : processName); + } + + public String getProcessName() { + return processName; + } + + public void setPermission(String permission) { + this.permission = TextUtils.safeIntern(permission); + } + + public String getPermission() { + return permission; + } + + @Override + public void setFrom(ParsedComponent other) { + super.setFrom(other); + if (other instanceof ParsedMainComponent) { + ParsedMainComponent otherMainComponent = (ParsedMainComponent) other; + this.setProcessName(otherMainComponent.getProcessName(), + otherMainComponent.getProcessName()); + this.setPermission(otherMainComponent.getPermission()); + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(this.processName); + dest.writeString(this.permission); + } + + public ParsedMainComponent() { + } + + protected ParsedMainComponent(Parcel in) { + super(in); + this.processName = TextUtils.safeIntern(in.readString()); + this.permission = TextUtils.safeIntern(in.readString()); + } + + public static final Creator<ParsedMainComponent> CREATOR = + new Creator<ParsedMainComponent>() { + @Override + public ParsedMainComponent createFromParcel(Parcel source) { + return new ParsedMainComponent(source); + } + + @Override + public ParsedMainComponent[] newArray(int size) { + return new ParsedMainComponent[size]; + } + }; + } + + public static class ParsedActivity extends ParsedMainComponent<ParsedActivityIntentInfo> + implements Parcelable { + + public boolean exported; + public int theme; + public int uiOptions; + + public String targetActivity; + + public String parentActivityName; + public String taskAffinity; + public int privateFlags; + + public int launchMode; + public int documentLaunchMode; + public int maxRecents; + public int configChanges; + public int softInputMode; + public int persistableMode; + public int lockTaskLaunchMode; + + public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + public int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; + + public float maxAspectRatio; + public boolean hasMaxAspectRatio; + + public float minAspectRatio; + public boolean hasMinAspectRatio; + + public String requestedVrComponent; + public int rotationAnimation = -1; + public int colorMode; + public int order; + + public ActivityInfo.WindowLayout windowLayout; + + @Override + public void setPackageName(String packageName) { + super.setPackageName(packageName); + for (ParsedIntentInfo intent : this.intents) { + intent.packageName = packageName; + } + } + + public boolean hasMaxAspectRatio() { + return hasMaxAspectRatio; + } + + public boolean hasMinAspectRatio() { + return hasMinAspectRatio; + } + + public void setMaxAspectRatio(int resizeMode, float maxAspectRatio) { + if (resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE + || resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { + // Resizeable activities can be put in any aspect ratio. + return; + } + + if (maxAspectRatio < 1.0f && maxAspectRatio != 0) { + // Ignore any value lesser than 1.0. + return; + } + + this.maxAspectRatio = maxAspectRatio; + hasMaxAspectRatio = true; + } + + public void setMinAspectRatio(int resizeMode, float minAspectRatio) { + if (resizeMode == RESIZE_MODE_RESIZEABLE + || resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { + // Resizeable activities can be put in any aspect ratio. + return; + } + + if (minAspectRatio < 1.0f && minAspectRatio != 0) { + // Ignore any value lesser than 1.0. + return; + } + + this.minAspectRatio = minAspectRatio; + hasMinAspectRatio = true; + } + + public void addIntent(ParsedActivityIntentInfo intent) { + this.intents.add(intent); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeBoolean(this.exported); + dest.writeInt(this.theme); + dest.writeInt(this.uiOptions); + dest.writeString(this.targetActivity); + dest.writeString(this.parentActivityName); + dest.writeString(this.taskAffinity); + dest.writeInt(this.privateFlags); + dest.writeInt(this.launchMode); + dest.writeInt(this.documentLaunchMode); + dest.writeInt(this.maxRecents); + dest.writeInt(this.configChanges); + dest.writeInt(this.softInputMode); + dest.writeInt(this.persistableMode); + dest.writeInt(this.lockTaskLaunchMode); + dest.writeInt(this.screenOrientation); + dest.writeInt(this.resizeMode); + dest.writeFloat(this.maxAspectRatio); + dest.writeBoolean(this.hasMaxAspectRatio); + dest.writeFloat(this.minAspectRatio); + dest.writeBoolean(this.hasMinAspectRatio); + dest.writeString(this.requestedVrComponent); + dest.writeInt(this.rotationAnimation); + dest.writeInt(this.colorMode); + dest.writeInt(this.order); + dest.writeBundle(this.metaData); + + if (windowLayout != null) { + dest.writeInt(1); + dest.writeInt(windowLayout.width); + dest.writeFloat(windowLayout.widthFraction); + dest.writeInt(windowLayout.height); + dest.writeFloat(windowLayout.heightFraction); + dest.writeInt(windowLayout.gravity); + dest.writeInt(windowLayout.minWidth); + dest.writeInt(windowLayout.minHeight); + } else { + dest.writeInt(0); + } + } + + public ParsedActivity() { + } + + protected ParsedActivity(Parcel in) { + super(in); + this.exported = in.readByte() != 0; + this.theme = in.readInt(); + this.uiOptions = in.readInt(); + this.targetActivity = in.readString(); + this.parentActivityName = in.readString(); + this.taskAffinity = in.readString(); + this.privateFlags = in.readInt(); + this.launchMode = in.readInt(); + this.documentLaunchMode = in.readInt(); + this.maxRecents = in.readInt(); + this.configChanges = in.readInt(); + this.softInputMode = in.readInt(); + this.persistableMode = in.readInt(); + this.lockTaskLaunchMode = in.readInt(); + this.screenOrientation = in.readInt(); + this.resizeMode = in.readInt(); + this.maxAspectRatio = in.readFloat(); + this.hasMaxAspectRatio = in.readByte() != 0; + this.minAspectRatio = in.readFloat(); + this.hasMinAspectRatio = in.readByte() != 0; + this.requestedVrComponent = in.readString(); + this.rotationAnimation = in.readInt(); + this.colorMode = in.readInt(); + this.order = in.readInt(); + this.metaData = in.readBundle(); + if (in.readInt() == 1) { + windowLayout = new ActivityInfo.WindowLayout(in); + } + } + + public static final Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() { + @Override + public ParsedActivity createFromParcel(Parcel source) { + return new ParsedActivity(source); + } + + @Override + public ParsedActivity[] newArray(int size) { + return new ParsedActivity[size]; + } + }; + } + + public static class ParsedService extends ParsedMainComponent<ParsedServiceIntentInfo> { + + public boolean exported; + public int flags; + public int foregroundServiceType; + public int order; + + @Override + public void setPackageName(String packageName) { + super.setPackageName(packageName); + for (ParsedIntentInfo intent : this.intents) { + intent.packageName = packageName; + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeBoolean(this.exported); + dest.writeBundle(this.metaData); + dest.writeInt(this.flags); + dest.writeInt(this.foregroundServiceType); + dest.writeInt(this.order); + } + + public ParsedService() { + } + + protected ParsedService(Parcel in) { + super(in); + this.exported = in.readByte() != 0; + this.metaData = in.readBundle(); + this.flags = in.readInt(); + this.foregroundServiceType = in.readInt(); + this.order = in.readInt(); + } + + public static final Creator<ParsedService> CREATOR = new Creator<ParsedService>() { + @Override + public ParsedService createFromParcel(Parcel source) { + return new ParsedService(source); + } + + @Override + public ParsedService[] newArray(int size) { + return new ParsedService[size]; + } + }; + } + + public static class ParsedProvider extends ParsedMainComponent<ParsedProviderIntentInfo> { + + protected boolean exported; + protected int flags; + protected int order; + private String authority; + protected boolean isSyncable; + private String readPermission; + private String writePermission; + protected boolean grantUriPermissions; + protected boolean forceUriPermissions; + protected boolean multiProcess; + protected int initOrder; + protected PatternMatcher[] uriPermissionPatterns; + protected PathPermission[] pathPermissions; + + protected void setFrom(ParsedProvider other) { + super.setFrom(other); + this.exported = other.exported; + + this.intents.clear(); + if (other.intents != null) { + this.intents.addAll(other.intents); + } + + this.flags = other.flags; + this.order = other.order; + this.setAuthority(other.getAuthority()); + this.isSyncable = other.isSyncable; + this.setReadPermission(other.getReadPermission()); + this.setWritePermission(other.getWritePermission()); + this.grantUriPermissions = other.grantUriPermissions; + this.forceUriPermissions = other.forceUriPermissions; + this.multiProcess = other.multiProcess; + this.initOrder = other.initOrder; + this.uriPermissionPatterns = other.uriPermissionPatterns; + this.pathPermissions = other.pathPermissions; + } + + @Override + public void setPackageName(String packageName) { + super.setPackageName(packageName); + for (ParsedIntentInfo intent : this.intents) { + intent.packageName = packageName; + } + } + + public boolean isExported() { + return exported; + } + + public List<ParsedProviderIntentInfo> getIntents() { + return intents; + } + + public int getFlags() { + return flags; + } + + public int getOrder() { + return order; + } + + public void setAuthority(String authority) { + this.authority = TextUtils.safeIntern(authority); + } + + public String getAuthority() { + return authority; + } + + public boolean isSyncable() { + return isSyncable; + } + + public void setReadPermission(String readPermission) { + this.readPermission = TextUtils.safeIntern(readPermission); + } + + public String getReadPermission() { + return readPermission; + } + + public void setWritePermission(String writePermission) { + this.writePermission = TextUtils.safeIntern(writePermission); + } + + public String getWritePermission() { + return writePermission; + } + + public boolean isGrantUriPermissions() { + return grantUriPermissions; + } + + public boolean isForceUriPermissions() { + return forceUriPermissions; + } + + public boolean isMultiProcess() { + return multiProcess; + } + + public int getInitOrder() { + return initOrder; + } + + public PatternMatcher[] getUriPermissionPatterns() { + return uriPermissionPatterns; + } + + public PathPermission[] getPathPermissions() { + return pathPermissions; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeBoolean(this.exported); + dest.writeInt(this.flags); + dest.writeInt(this.order); + dest.writeString(this.authority); + dest.writeBoolean(this.isSyncable); + dest.writeString(this.readPermission); + dest.writeString(this.writePermission); + dest.writeBoolean(this.grantUriPermissions); + dest.writeBoolean(this.forceUriPermissions); + dest.writeBoolean(this.multiProcess); + dest.writeInt(this.initOrder); + dest.writeTypedArray(this.uriPermissionPatterns, flags); + dest.writeTypedArray(this.pathPermissions, flags); + } + + public ParsedProvider() { + } + + protected ParsedProvider(Parcel in) { + super(in); + this.exported = in.readByte() != 0; + this.flags = in.readInt(); + this.order = in.readInt(); + this.authority = TextUtils.safeIntern(in.readString()); + this.isSyncable = in.readByte() != 0; + this.readPermission = TextUtils.safeIntern(in.readString()); + this.writePermission = TextUtils.safeIntern(in.readString()); + this.grantUriPermissions = in.readByte() != 0; + this.forceUriPermissions = in.readByte() != 0; + this.multiProcess = in.readByte() != 0; + this.initOrder = in.readInt(); + this.uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR); + this.pathPermissions = in.createTypedArray(PathPermission.CREATOR); + } + + public static final Creator<ParsedProvider> CREATOR = new Creator<ParsedProvider>() { + @Override + public ParsedProvider createFromParcel(Parcel source) { + return new ParsedProvider(source); + } + + @Override + public ParsedProvider[] newArray(int size) { + return new ParsedProvider[size]; + } + }; + } + + public static class ParsedPermission extends ParsedComponent<ParsedIntentInfo> { + + public String backgroundPermission; + private String group; + public int requestRes; + public int protectionLevel; + public boolean tree; + + public ParsedPermissionGroup parsedPermissionGroup; + + public void setName(String className) { + this.className = className; + } + + public void setGroup(String group) { + this.group = TextUtils.safeIntern(group); + } + + public String getGroup() { + return group; + } + + public boolean isRuntime() { + return getProtection() == PermissionInfo.PROTECTION_DANGEROUS; + } + + public boolean isAppOp() { + return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0; + } + + @PermissionInfo.Protection + public int getProtection() { + return protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; + } + + public int getProtectionFlags() { + return protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE; + } + + public int calculateFootprint() { + int size = getName().length(); + if (nonLocalizedLabel != null) { + size += nonLocalizedLabel.length(); + } + return size; + } + + public ParsedPermission() { + } + + public ParsedPermission(ParsedPermission other) { + // TODO(b/135203078): Better way to copy this? Maybe refactor to the point where copy + // isn't needed. + this.className = other.className; + this.icon = other.icon; + this.labelRes = other.labelRes; + this.nonLocalizedLabel = other.nonLocalizedLabel; + this.logo = other.logo; + this.banner = other.banner; + this.descriptionRes = other.descriptionRes; + this.enabled = other.enabled; + this.directBootAware = other.directBootAware; + this.flags = other.flags; + this.setSplitName(other.getSplitName()); + this.setPackageName(other.getPackageName()); + + this.intents.addAll(other.intents); + + if (other.metaData != null) { + this.metaData = new Bundle(); + this.metaData.putAll(other.metaData); + } + + this.backgroundPermission = other.backgroundPermission; + this.setGroup(other.group); + this.requestRes = other.requestRes; + this.protectionLevel = other.protectionLevel; + this.tree = other.tree; + + this.parsedPermissionGroup = other.parsedPermissionGroup; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(this.backgroundPermission); + dest.writeString(this.group); + dest.writeInt(this.requestRes); + dest.writeInt(this.protectionLevel); + dest.writeBoolean(this.tree); + dest.writeParcelable(this.parsedPermissionGroup, flags); + } + + protected ParsedPermission(Parcel in) { + super(in); + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + this.backgroundPermission = in.readString(); + this.group = TextUtils.safeIntern(in.readString()); + this.requestRes = in.readInt(); + this.protectionLevel = in.readInt(); + this.tree = in.readBoolean(); + this.parsedPermissionGroup = in.readParcelable(boot); + } + + public static final Creator<ParsedPermission> CREATOR = new Creator<ParsedPermission>() { + @Override + public ParsedPermission createFromParcel(Parcel source) { + return new ParsedPermission(source); + } + + @Override + public ParsedPermission[] newArray(int size) { + return new ParsedPermission[size]; + } + }; + } + + public static class ParsedPermissionGroup extends ParsedComponent<ParsedIntentInfo> { + + public int requestDetailResourceId; + public int backgroundRequestResourceId; + public int backgroundRequestDetailResourceId; + + public int requestRes; + public int priority; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(this.requestDetailResourceId); + dest.writeInt(this.backgroundRequestResourceId); + dest.writeInt(this.backgroundRequestDetailResourceId); + dest.writeInt(this.requestRes); + dest.writeInt(this.priority); + } + + public ParsedPermissionGroup() { + } + + protected ParsedPermissionGroup(Parcel in) { + super(in); + this.requestDetailResourceId = in.readInt(); + this.backgroundRequestResourceId = in.readInt(); + this.backgroundRequestDetailResourceId = in.readInt(); + this.requestRes = in.readInt(); + this.priority = in.readInt(); + } + + public static final Creator<ParsedPermissionGroup> CREATOR = + new Creator<ParsedPermissionGroup>() { + @Override + public ParsedPermissionGroup createFromParcel(Parcel source) { + return new ParsedPermissionGroup(source); + } + + @Override + public ParsedPermissionGroup[] newArray(int size) { + return new ParsedPermissionGroup[size]; + } + }; + } + + public static class ParsedInstrumentation extends ParsedComponent<ParsedIntentInfo> { + + private String targetPackage; + private String targetProcesses; + public boolean handleProfiling; + public boolean functionalTest; + + public ParsedInstrumentation() { + } + + public void setTargetPackage(String targetPackage) { + this.targetPackage = TextUtils.safeIntern(targetPackage); + } + + public String getTargetPackage() { + return targetPackage; + } + + public void setTargetProcesses(String targetProcesses) { + this.targetProcesses = TextUtils.safeIntern(targetProcesses); + } + + public String getTargetProcesses() { + return targetProcesses; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(this.targetPackage); + dest.writeString(this.targetProcesses); + dest.writeBoolean(this.handleProfiling); + dest.writeBoolean(this.functionalTest); + } + + protected ParsedInstrumentation(Parcel in) { + super(in); + this.targetPackage = TextUtils.safeIntern(in.readString()); + this.targetProcesses = TextUtils.safeIntern(in.readString()); + this.handleProfiling = in.readByte() != 0; + this.functionalTest = in.readByte() != 0; + } + + public static final Creator<ParsedInstrumentation> CREATOR = + new Creator<ParsedInstrumentation>() { + @Override + public ParsedInstrumentation createFromParcel(Parcel source) { + return new ParsedInstrumentation(source); + } + + @Override + public ParsedInstrumentation[] newArray(int size) { + return new ParsedInstrumentation[size]; + } + }; + } + + public static ParsedActivity parseActivity( + String[] separateProcesses, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, int flags, String[] outError, + boolean receiver, boolean hardwareAccelerated) + throws XmlPullParserException, IOException { + + TypedArray sa = null; + boolean visibleToEphemeral; + boolean setExported; + + int targetSdkVersion = parsingPackage.getTargetSdkVersion(); + String packageName = parsingPackage.getPackageName(); + String packageProcessName = parsingPackage.getProcessName(); + ParsedActivity result = new ParsedActivity(); + + try { + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity); + + String tag = receiver ? "<receiver>" : "<activity>"; + + String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_name, 0); + if (name == null) { + outError[0] = tag + " does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = tag + " invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestActivity_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivity_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivity_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivity_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivity_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + CharSequence pname; + if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { + pname = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_process, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + pname = sa.getNonResourceString(R.styleable.AndroidManifestActivity_process); + } + + result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName, + packageProcessName, pname, + flags, separateProcesses, outError)); + + result.descriptionRes = sa.getResourceId( + R.styleable.AndroidManifestActivity_description, 0); + + result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivity_enabled, true); + + setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported); + if (setExported) { + result.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, + false); + } + + result.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0); + + result.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, + parsingPackage.getUiOptions()); + + String parentName = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivity_parentActivityName, + Configuration.NATIVE_CONFIG_VERSION); + if (parentName != null) { + String parentClassName = ApkParseUtils.buildClassName(packageName, parentName); + if (parentClassName == null) { + Log.e(TAG, + "Activity " + result.className + + " specified invalid parentActivityName " + + parentName); + } else { + result.parentActivityName = parentClassName; + } + } + + String str; + str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0); + if (str == null) { + result.setPermission(parsingPackage.getPermission()); + } else { + result.setPermission(str); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivity_taskAffinity, + Configuration.NATIVE_CONFIG_VERSION); + result.taskAffinity = PackageParser.buildTaskAffinityName( + packageName, + parsingPackage.getTaskAffinity(), str, outError); + + result.setSplitName( + sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0)); + + result.flags = 0; + if (sa.getBoolean( + R.styleable.AndroidManifestActivity_multiprocess, false)) { + result.flags |= ActivityInfo.FLAG_MULTIPROCESS; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) { + result.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) { + result.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) { + result.flags |= ActivityInfo.FLAG_NO_HISTORY; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) { + result.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) { + result.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) { + result.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting, + (parsingPackage.getFlags() & ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) + != 0)) { + result.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, + false)) { + result.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false) + || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) { + result.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) { + result.flags |= ActivityInfo.FLAG_IMMERSIVE; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) { + result.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY; + } + + boolean directBootAware; + + if (!receiver) { + if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated, + hardwareAccelerated)) { + result.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; + } + + result.launchMode = sa.getInt( + R.styleable.AndroidManifestActivity_launchMode, + ActivityInfo.LAUNCH_MULTIPLE); + result.documentLaunchMode = sa.getInt( + R.styleable.AndroidManifestActivity_documentLaunchMode, + ActivityInfo.DOCUMENT_LAUNCH_NONE); + result.maxRecents = sa.getInt( + R.styleable.AndroidManifestActivity_maxRecents, + ActivityTaskManager.getDefaultAppRecentsLimitStatic()); + result.configChanges = PackageParser.getActivityConfigChanges( + sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0), + sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0)); + result.softInputMode = sa.getInt( + R.styleable.AndroidManifestActivity_windowSoftInputMode, 0); + + result.persistableMode = sa.getInteger( + R.styleable.AndroidManifestActivity_persistableMode, + ActivityInfo.PERSIST_ROOT_ONLY); + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) { + result.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, + false)) { + result.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, + false)) { + result.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) { + result.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING; + } + + int screenOrientation = sa.getInt( + R.styleable.AndroidManifestActivity_screenOrientation, + SCREEN_ORIENTATION_UNSPECIFIED); + result.screenOrientation = screenOrientation; + + int resizeMode = getActivityResizeMode(parsingPackage, sa, screenOrientation); + result.resizeMode = resizeMode; + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture, + false)) { + result.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) { + result.flags |= FLAG_ALWAYS_FOCUSABLE; + } + + if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio) + && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio) + == TypedValue.TYPE_FLOAT) { + result.setMaxAspectRatio(resizeMode, + sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio, + 0 /*default*/)); + } + + if (sa.hasValue(R.styleable.AndroidManifestActivity_minAspectRatio) + && sa.getType(R.styleable.AndroidManifestActivity_minAspectRatio) + == TypedValue.TYPE_FLOAT) { + result.setMinAspectRatio(resizeMode, + sa.getFloat(R.styleable.AndroidManifestActivity_minAspectRatio, + 0 /*default*/)); + } + + result.lockTaskLaunchMode = + sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0); + + directBootAware = sa.getBoolean( + R.styleable.AndroidManifestActivity_directBootAware, + false); + + result.requestedVrComponent = + sa.getString(R.styleable.AndroidManifestActivity_enableVrMode); + + result.rotationAnimation = + sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, + ROTATION_ANIMATION_UNSPECIFIED); + + result.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode, + ActivityInfo.COLOR_MODE_DEFAULT); + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) { + result.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) { + result.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_inheritShowWhenLocked, + false)) { + result.privateFlags |= ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED; + } + } else { + result.launchMode = ActivityInfo.LAUNCH_MULTIPLE; + result.configChanges = 0; + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) { + result.flags |= ActivityInfo.FLAG_SINGLE_USER; + } + directBootAware = sa.getBoolean( + R.styleable.AndroidManifestActivity_directBootAware, + false); + } + + result.directBootAware = directBootAware; + + if (directBootAware) { + parsingPackage.setPartiallyDirectBootAware(true); + } + + // can't make this final; we may set it later via meta-data + visibleToEphemeral = sa.getBoolean( + R.styleable.AndroidManifestActivity_visibleToInstantApps, false); + if (visibleToEphemeral) { + result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; + parsingPackage.setVisibleToInstantApps(true); + } + } finally { + if (sa != null) { + sa.recycle(); + } + } + + + if (receiver && (parsingPackage.getPrivateFlags() + & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { + // A heavy-weight application can not have receives in its main process + if (result.getProcessName().equals(packageName)) { + outError[0] = "Heavy-weight applications can not have receivers in main process"; + return null; + } + } + + if (outError[0] != null) { + return null; + } + + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + if (parser.getName().equals("intent-filter")) { + ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName, + result.className); + if (!parseIntentInfo(intentInfo, parsingPackage, res, parser, + true /*allowGlobs*/, + true /*allowAutoVerify*/, outError)) { + return null; + } + if (intentInfo.countActions() == 0) { + Slog.w(TAG, "No actions in intent filter at " + + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } else { + result.order = Math.max(intentInfo.getOrder(), result.order); + result.addIntent(intentInfo); + } + // adjust activity flags when we implicitly expose it via a browsable filter + final int visibility = visibleToEphemeral + ? IntentFilter.VISIBILITY_EXPLICIT + : !receiver && isImplicitlyExposedIntent(intentInfo) + ? IntentFilter.VISIBILITY_IMPLICIT + : IntentFilter.VISIBILITY_NONE; + intentInfo.setVisibilityToInstantApp(visibility); + if (intentInfo.isVisibleToInstantApp()) { + result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; + } + if (intentInfo.isImplicitlyVisibleToInstantApp()) { + result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; + } + if (PackageParser.LOG_UNSAFE_BROADCASTS && receiver + && (targetSdkVersion >= Build.VERSION_CODES.O)) { + for (int i = 0; i < intentInfo.countActions(); i++) { + final String action = intentInfo.getAction(i); + if (action == null || !action.startsWith("android.")) continue; + if (!PackageParser.SAFE_BROADCASTS.contains(action)) { + Slog.w(TAG, "Broadcast " + action + " may never be delivered to " + + packageName + " as requested at: " + + parser.getPositionDescription()); + } + } + } + } else if (!receiver && parser.getName().equals("preferred")) { + ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName, + result.className); + if (!parseIntentInfo(intentInfo, parsingPackage, res, parser, + false /*allowGlobs*/, + false /*allowAutoVerify*/, outError)) { + return null; + } + // adjust activity flags when we implicitly expose it via a browsable filter + final int visibility = visibleToEphemeral + ? IntentFilter.VISIBILITY_EXPLICIT + : !receiver && isImplicitlyExposedIntent(intentInfo) + ? IntentFilter.VISIBILITY_IMPLICIT + : IntentFilter.VISIBILITY_NONE; + intentInfo.setVisibilityToInstantApp(visibility); + if (intentInfo.isVisibleToInstantApp()) { + result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; + } + if (intentInfo.isImplicitlyVisibleToInstantApp()) { + result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; + } + + if (intentInfo.countActions() == 0) { + Slog.w(TAG, "No actions in preferred at " + + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } else { + parsingPackage.addPreferredActivityFilter(intentInfo); + } + } else if (parser.getName().equals("meta-data")) { + if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, + result.metaData, + outError)) == null) { + return null; + } + } else if (!receiver && parser.getName().equals("layout")) { + result.windowLayout = parseLayout(res, parser); + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Problem in package " + parsingPackage.getBaseCodePath() + ":"); + if (receiver) { + Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName() + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } else { + Slog.w(TAG, "Unknown element under <activity>: " + parser.getName() + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } + XmlUtils.skipCurrentTag(parser); + continue; + } else { + if (receiver) { + outError[0] = "Bad element under <receiver>: " + parser.getName(); + } else { + outError[0] = "Bad element under <activity>: " + parser.getName(); + } + return null; + } + } + } + + if (!setExported) { + result.exported = result.intents.size() > 0; + } + + return result; + } + + public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) { + return intentInfo.hasCategory(Intent.CATEGORY_BROWSABLE) + || intentInfo.hasAction(Intent.ACTION_SEND) + || intentInfo.hasAction(Intent.ACTION_SENDTO) + || intentInfo.hasAction(Intent.ACTION_SEND_MULTIPLE); + } + + public static int getActivityResizeMode( + ParsingPackage parsingPackage, + TypedArray sa, + int screenOrientation + ) { + int privateFlags = parsingPackage.getPrivateFlags(); + final boolean appExplicitDefault = (privateFlags + & (ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE + | ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0; + + if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity) + || appExplicitDefault) { + // Activity or app explicitly set if it is resizeable or not; + final boolean appResizeable = (privateFlags + & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0; + if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, + appResizeable)) { + return ActivityInfo.RESIZE_MODE_RESIZEABLE; + } else { + return ActivityInfo.RESIZE_MODE_UNRESIZEABLE; + } + } + + if ((privateFlags + & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) + != 0) { + // The activity or app didn't explicitly set the resizing option, however we want to + // make it resize due to the sdk version it is targeting. + return ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; + } + + // resize preference isn't set and target sdk version doesn't support resizing apps by + // default. For the app to be resizeable if it isn't fixed orientation or immersive. + if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; + } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; + } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; + } else { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; + } + } + + public static ParsedService parseService( + String[] separateProcesses, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, int flags, String[] outError + ) throws XmlPullParserException, IOException { + TypedArray sa = null; + boolean visibleToEphemeral; + boolean setExported; + + String packageName = parsingPackage.getPackageName(); + String packageProcessName = parsingPackage.getProcessName(); + ParsedService result = new ParsedService(); + + try { + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestService); + + String name = sa.getNonConfigurationString(R.styleable.AndroidManifestService_name, 0); + if (name == null) { + outError[0] = "<service> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<service> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestService_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestService_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestService_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestService_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestService_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + CharSequence pname; + if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { + pname = sa.getNonConfigurationString(R.styleable.AndroidManifestService_process, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + pname = sa.getNonResourceString(R.styleable.AndroidManifestService_process); + } + + result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName, + packageProcessName, pname, + flags, separateProcesses, outError)); + + result.descriptionRes = sa.getResourceId( + R.styleable.AndroidManifestService_description, 0); + + result.enabled = sa.getBoolean(R.styleable.AndroidManifestService_enabled, true); + + setExported = sa.hasValue( + R.styleable.AndroidManifestService_exported); + if (setExported) { + result.exported = sa.getBoolean( + R.styleable.AndroidManifestService_exported, false); + } + + String str = sa.getNonConfigurationString( + R.styleable.AndroidManifestService_permission, 0); + if (str == null) { + result.setPermission(parsingPackage.getPermission()); + } else { + result.setPermission(str); + } + + result.setSplitName( + sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0)); + + result.foregroundServiceType = sa.getInt( + R.styleable.AndroidManifestService_foregroundServiceType, + ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE); + + result.flags = 0; + if (sa.getBoolean( + R.styleable.AndroidManifestService_stopWithTask, + false)) { + result.flags |= ServiceInfo.FLAG_STOP_WITH_TASK; + } + if (sa.getBoolean( + R.styleable.AndroidManifestService_isolatedProcess, + false)) { + result.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS; + } + if (sa.getBoolean( + R.styleable.AndroidManifestService_externalService, + false)) { + result.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE; + } + if (sa.getBoolean( + R.styleable.AndroidManifestService_useAppZygote, + false)) { + result.flags |= ServiceInfo.FLAG_USE_APP_ZYGOTE; + } + if (sa.getBoolean( + R.styleable.AndroidManifestService_singleUser, + false)) { + result.flags |= ServiceInfo.FLAG_SINGLE_USER; + } + + result.directBootAware = sa.getBoolean( + R.styleable.AndroidManifestService_directBootAware, + false); + if (result.directBootAware) { + parsingPackage.setPartiallyDirectBootAware(true); + } + + visibleToEphemeral = sa.getBoolean( + R.styleable.AndroidManifestService_visibleToInstantApps, false); + if (visibleToEphemeral) { + result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP; + parsingPackage.setVisibleToInstantApps(true); + } + } finally { + if (sa != null) { + sa.recycle(); + } + } + + if (parsingPackage.cantSaveState()) { + // A heavy-weight application can not have services in its main process + // We can do direct compare because we intern all strings. + if (Objects.equals(result.getProcessName(), parsingPackage.getPackageName())) { + outError[0] = "Heavy-weight applications can not have services in main process"; + return null; + } + } + + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + if (parser.getName().equals("intent-filter")) { + ParsedServiceIntentInfo intent = new ParsedServiceIntentInfo(packageName, + result.className); + if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/, + false /*allowAutoVerify*/, + outError)) { + return null; + } + if (visibleToEphemeral) { + intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); + result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP; + } + result.order = Math.max(intent.getOrder(), result.order); + result.intents.add(intent); + } else if (parser.getName().equals("meta-data")) { + if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, + result.metaData, + outError)) == null) { + return null; + } + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <service>: " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + outError[0] = "Bad element under <service>: " + parser.getName(); + return null; + } + } + } + + if (!setExported) { + result.exported = result.intents.size() > 0; + } + + return result; + } + + public static ParsedProvider parseProvider( + String[] separateProcesses, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, int flags, String[] outError) + throws XmlPullParserException, IOException { + TypedArray sa = null; + String cpname; + boolean visibleToEphemeral; + + int targetSdkVersion = parsingPackage.getTargetSdkVersion(); + String packageName = parsingPackage.getPackageName(); + String packageProcessName = parsingPackage.getProcessName(); + ParsedProvider result = new ParsedProvider(); + + try { + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestProvider); + + String name = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_name, 0); + if (name == null) { + outError[0] = "<provider> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<provider> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestProvider_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestProvider_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestProvider_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestProvider_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestProvider_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + CharSequence pname; + if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { + pname = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_process, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + pname = sa.getNonResourceString(R.styleable.AndroidManifestProvider_process); + } + + result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName, + packageProcessName, pname, + flags, separateProcesses, outError)); + + result.descriptionRes = sa.getResourceId( + R.styleable.AndroidManifestProvider_description, 0); + + result.enabled = sa.getBoolean(R.styleable.AndroidManifestProvider_enabled, true); + + boolean providerExportedDefault = false; + + if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { + // For compatibility, applications targeting API level 16 or lower + // should have their content providers exported by default, unless they + // specify otherwise. + providerExportedDefault = true; + } + + result.exported = sa.getBoolean( + R.styleable.AndroidManifestProvider_exported, + providerExportedDefault); + + cpname = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_authorities, 0); + + result.isSyncable = sa.getBoolean( + R.styleable.AndroidManifestProvider_syncable, + false); + + String permission = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_permission, 0); + String str = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_readPermission, 0); + if (str == null) { + str = permission; + } + if (str == null) { + result.setReadPermission(parsingPackage.getPermission()); + } else { + result.setReadPermission(str); + } + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_writePermission, 0); + if (str == null) { + str = permission; + } + if (str == null) { + result.setWritePermission(parsingPackage.getPermission()); + } else { + result.setWritePermission(str); + } + + result.grantUriPermissions = sa.getBoolean( + R.styleable.AndroidManifestProvider_grantUriPermissions, + false); + + result.forceUriPermissions = sa.getBoolean( + R.styleable.AndroidManifestProvider_forceUriPermissions, + false); + + result.multiProcess = sa.getBoolean( + R.styleable.AndroidManifestProvider_multiprocess, + false); + + result.initOrder = sa.getInt( + R.styleable.AndroidManifestProvider_initOrder, + 0); + + result.setSplitName( + sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_splitName, 0)); + + result.flags = 0; + + if (sa.getBoolean( + R.styleable.AndroidManifestProvider_singleUser, + false)) { + result.flags |= ProviderInfo.FLAG_SINGLE_USER; + } + + result.directBootAware = sa.getBoolean( + R.styleable.AndroidManifestProvider_directBootAware, + false); + if (result.directBootAware) { + parsingPackage.setPartiallyDirectBootAware(true); + } + + visibleToEphemeral = + sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false); + if (visibleToEphemeral) { + result.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP; + parsingPackage.setVisibleToInstantApps(true); + } + } finally { + if (sa != null) { + sa.recycle(); + } + } + + if ((parsingPackage.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) + != 0) { + // A heavy-weight application can not have providers in its main process + if (result.getProcessName().equals(packageName)) { + outError[0] = "Heavy-weight applications can not have providers in main process"; + return null; + } + } + + if (cpname == null) { + outError[0] = "<provider> does not include authorities attribute"; + return null; + } + if (cpname.length() <= 0) { + outError[0] = "<provider> has empty authorities attribute"; + return null; + } + result.setAuthority(cpname); + + if (!parseProviderTags(parsingPackage, res, parser, visibleToEphemeral, result, outError)) { + return null; + } + + return result; + } + + public static ParsedQueriesIntentInfo parsedParsedQueriesIntentInfo( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + String[] outError + ) throws IOException, XmlPullParserException { + ParsedQueriesIntentInfo intentInfo = new ParsedQueriesIntentInfo( + parsingPackage.getPackageName(), + null + ); + if (!parseIntentInfo( + intentInfo, + parsingPackage, + res, + parser, + true /*allowGlobs*/, + true /*allowAutoVerify*/, + outError + )) { + return null; + } + return intentInfo; + } + + private static boolean parseProviderTags( + ParsingPackage parsingPackage, + Resources res, XmlResourceParser parser, + boolean visibleToEphemeral, ParsedProvider outInfo, String[] outError) + throws XmlPullParserException, IOException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + if (parser.getName().equals("intent-filter")) { + ParsedProviderIntentInfo intent = new ParsedProviderIntentInfo( + parsingPackage.getPackageName(), outInfo.className); + if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/, + false /*allowAutoVerify*/, + outError)) { + return false; + } + if (visibleToEphemeral) { + intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); + outInfo.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP; + } + outInfo.order = Math.max(intent.getOrder(), outInfo.order); + outInfo.intents.add(intent); + + } else if (parser.getName().equals("meta-data")) { + Bundle metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, + outInfo.metaData, outError); + if (metaData == null) { + return false; + } else { + outInfo.metaData = metaData; + } + + } else if (parser.getName().equals("grant-uri-permission")) { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestGrantUriPermission); + + PatternMatcher pa = null; + + String str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_path, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); + } + + sa.recycle(); + + if (pa != null) { + if (outInfo.uriPermissionPatterns == null) { + outInfo.uriPermissionPatterns = new PatternMatcher[1]; + outInfo.uriPermissionPatterns[0] = pa; + } else { + final int N = outInfo.uriPermissionPatterns.length; + PatternMatcher[] newp = new PatternMatcher[N + 1]; + System.arraycopy(outInfo.uriPermissionPatterns, 0, newp, 0, N); + newp[N] = pa; + outInfo.uriPermissionPatterns = newp; + } + outInfo.grantUriPermissions = true; + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <path-permission>: " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; + return false; + } + } + XmlUtils.skipCurrentTag(parser); + + } else if (parser.getName().equals("path-permission")) { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestPathPermission); + + PathPermission pa = null; + + String permission = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_permission, 0); + String readPermission = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_readPermission, 0); + if (readPermission == null) { + readPermission = permission; + } + String writePermission = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_writePermission, 0); + if (writePermission == null) { + writePermission = permission; + } + + boolean havePerm = false; + if (readPermission != null) { + readPermission = readPermission.intern(); + havePerm = true; + } + if (writePermission != null) { + writePermission = writePermission.intern(); + havePerm = true; + } + + if (!havePerm) { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + outError[0] = "No readPermission or writePermssion for <path-permission>"; + return false; + } + } + + String path = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_path, 0); + if (path != null) { + pa = new PathPermission(path, + PatternMatcher.PATTERN_LITERAL, readPermission, writePermission); + } + + path = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_pathPrefix, 0); + if (path != null) { + pa = new PathPermission(path, + PatternMatcher.PATTERN_PREFIX, readPermission, writePermission); + } + + path = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_pathPattern, 0); + if (path != null) { + pa = new PathPermission(path, + PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission); + } + + path = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0); + if (path != null) { + pa = new PathPermission(path, + PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, writePermission); + } + + sa.recycle(); + + if (pa != null) { + if (outInfo.pathPermissions == null) { + outInfo.pathPermissions = new PathPermission[1]; + outInfo.pathPermissions[0] = pa; + } else { + final int N = outInfo.pathPermissions.length; + PathPermission[] newp = new PathPermission[N + 1]; + System.arraycopy(outInfo.pathPermissions, 0, newp, 0, N); + newp[N] = pa; + outInfo.pathPermissions = newp; + } + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; + return false; + } + XmlUtils.skipCurrentTag(parser); + + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <provider>: " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + outError[0] = "Bad element under <provider>: " + parser.getName(); + return false; + } + } + } + return true; + } + + public static ParsedActivity parseActivityAlias( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + String[] outError) + throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestActivityAlias); + + String targetActivity = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivityAlias_targetActivity, + Configuration.NATIVE_CONFIG_VERSION); + if (targetActivity == null) { + outError[0] = "<activity-alias> does not specify android:targetActivity"; + sa.recycle(); + return null; + } + + String packageName = parsingPackage.getPackageName(); + targetActivity = ApkParseUtils.buildClassName(packageName, targetActivity); + if (targetActivity == null) { + outError[0] = "Empty class name in package " + packageName; + sa.recycle(); + return null; + } + + ParsedActivity target = null; + + List<ParsedActivity> activities = parsingPackage.getActivities(); + final int NA = activities.size(); + for (int i = 0; i < NA; i++) { + ParsedActivity t = activities.get(i); + if (targetActivity.equals(t.className)) { + target = t; + break; + } + } + + if (target == null) { + outError[0] = "<activity-alias> target activity " + targetActivity + + " not found in manifest with activities = " + parsingPackage.getActivities() + + ", parsedActivities = " + activities; + sa.recycle(); + return null; + } + + ParsedActivity result = new ParsedActivity(); + result.setPackageNameInternal(target.getPackageName()); + result.targetActivity = targetActivity; + result.configChanges = target.configChanges; + result.flags = target.flags; + result.privateFlags = target.privateFlags; + result.icon = target.icon; + result.logo = target.logo; + result.banner = target.banner; + result.labelRes = target.labelRes; + result.nonLocalizedLabel = target.nonLocalizedLabel; + result.launchMode = target.launchMode; + result.lockTaskLaunchMode = target.lockTaskLaunchMode; + result.descriptionRes = target.descriptionRes; + result.screenOrientation = target.screenOrientation; + result.taskAffinity = target.taskAffinity; + result.theme = target.theme; + result.softInputMode = target.softInputMode; + result.uiOptions = target.uiOptions; + result.parentActivityName = target.parentActivityName; + result.maxRecents = target.maxRecents; + result.windowLayout = target.windowLayout; + result.resizeMode = target.resizeMode; + result.maxAspectRatio = target.maxAspectRatio; + result.hasMaxAspectRatio = target.hasMaxAspectRatio; + result.minAspectRatio = target.minAspectRatio; + result.hasMinAspectRatio = target.hasMinAspectRatio; + result.requestedVrComponent = target.requestedVrComponent; + result.directBootAware = target.directBootAware; + + result.setProcessName(parsingPackage.getAppInfoProcessName(), target.getProcessName()); + + // Not all attributes from the target ParsedActivity are copied to the alias. + // Careful when adding an attribute and determine whether or not it should be copied. +// result.enabled = target.enabled; +// result.exported = target.exported; +// result.permission = target.permission; +// result.splitName = target.splitName; +// result.documentLaunchMode = target.documentLaunchMode; +// result.persistableMode = target.persistableMode; +// result.rotationAnimation = target.rotationAnimation; +// result.colorMode = target.colorMode; +// result.intents.addAll(target.intents); +// result.order = target.order; +// result.metaData = target.metaData; + + String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivityAlias_name, + 0); + if (name == null) { + outError[0] = "<activity-alias> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<activity-alias> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestActivityAlias_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivityAlias_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + result.descriptionRes = sa.getResourceId( + R.styleable.AndroidManifestActivityAlias_description, 0); + + result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivityAlias_enabled, true); + + final boolean setExported = sa.hasValue( + R.styleable.AndroidManifestActivityAlias_exported); + if (setExported) { + result.exported = sa.getBoolean( + R.styleable.AndroidManifestActivityAlias_exported, false); + } + + String str; + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivityAlias_permission, 0); + if (str != null) { + result.setPermission(str); + } + + String parentName = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivityAlias_parentActivityName, + Configuration.NATIVE_CONFIG_VERSION); + if (parentName != null) { + String parentClassName = ApkParseUtils.buildClassName(result.getPackageName(), + parentName); + if (parentClassName == null) { + Log.e(TAG, "Activity alias " + result.className + + " specified invalid parentActivityName " + parentName); + outError[0] = null; + } else { + result.parentActivityName = parentClassName; + } + } + + // TODO add visibleToInstantApps attribute to activity alias + final boolean visibleToEphemeral = + ((result.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0); + + sa.recycle(); + + if (outError[0] != null) { + return null; + } + + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("intent-filter")) { + ParsedActivityIntentInfo intent = new ParsedActivityIntentInfo(packageName, + result.className); + if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/, + true /*allowAutoVerify*/, outError)) { + return null; + } + if (intent.countActions() == 0) { + Slog.w(TAG, "No actions in intent filter at " + + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } else { + result.order = Math.max(intent.getOrder(), result.order); + result.addIntent(intent); + } + // adjust activity flags when we implicitly expose it via a browsable filter + final int visibility = visibleToEphemeral + ? IntentFilter.VISIBILITY_EXPLICIT + : isImplicitlyExposedIntent(intent) + ? IntentFilter.VISIBILITY_IMPLICIT + : IntentFilter.VISIBILITY_NONE; + intent.setVisibilityToInstantApp(visibility); + if (intent.isVisibleToInstantApp()) { + result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; + } + if (intent.isImplicitlyVisibleToInstantApp()) { + result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; + } + } else if (tagName.equals("meta-data")) { + if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, + result.metaData, + outError)) == null) { + return null; + } + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <activity-alias>: " + tagName + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + outError[0] = "Bad element under <activity-alias>: " + tagName; + return null; + } + } + } + + if (!setExported) { + result.exported = result.intents.size() > 0; + } + + return result; + } + + public static ParsedPermission parsePermission( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + String[] outError + ) throws IOException, XmlPullParserException { + TypedArray sa = null; + String packageName = parsingPackage.getPackageName(); + ParsedPermission result = new ParsedPermission(); + + try { + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission); + + String name = sa.getNonConfigurationString(R.styleable.AndroidManifestPermission_name, + 0); + if (name == null) { + outError[0] = "<permission> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<permission> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestPermission_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermission_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermission_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermission_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermission_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + result.descriptionRes = sa.getResourceId( + R.styleable.AndroidManifestPermission_description, 0); + + if (sa.hasValue( + R.styleable.AndroidManifestPermission_backgroundPermission)) { + if ("android".equals(packageName)) { + result.backgroundPermission = sa.getNonResourceString( + R.styleable + .AndroidManifestPermission_backgroundPermission); + } else { + Slog.w(TAG, packageName + " defines a background permission. Only the " + + "'android' package can do that."); + } + } + + // Note: don't allow this value to be a reference to a resource + // that may change. + result.setGroup(sa.getNonResourceString( + R.styleable.AndroidManifestPermission_permissionGroup)); + + result.requestRes = sa.getResourceId( + R.styleable.AndroidManifestPermission_request, 0); + + result.protectionLevel = sa.getInt( + R.styleable.AndroidManifestPermission_protectionLevel, + PermissionInfo.PROTECTION_NORMAL); + + result.flags = sa.getInt( + R.styleable.AndroidManifestPermission_permissionFlags, 0); + + // For now only platform runtime permissions can be restricted + if (!result.isRuntime() || !"android".equals(result.getPackageName())) { + result.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED; + result.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED; + } else { + // The platform does not get to specify conflicting permissions + if ((result.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0 + && (result.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) { + throw new IllegalStateException("Permission cannot be both soft and hard" + + " restricted: " + result.getName()); + } + } + + } finally { + if (sa != null) { + sa.recycle(); + } + } + + if (result.protectionLevel == -1) { + outError[0] = "<permission> does not specify protectionLevel"; + return null; + } + + result.protectionLevel = PermissionInfo.fixProtectionLevel(result.protectionLevel); + + if (result.getProtectionFlags() != 0) { + if ((result.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0 + && (result.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) + == 0 + && (result.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) != + PermissionInfo.PROTECTION_SIGNATURE) { + outError[0] = "<permission> protectionLevel specifies a non-instant flag but is " + + "not based on signature type"; + return null; + } + } + + boolean success = parseAllMetaData(parsingPackage, res, parser, + "<permission>", result, outError); + if (!success || outError[0] != null) { + return null; + } + + return result; + } + + public static ParsedPermission parsePermissionTree( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + String[] outError + ) throws IOException, XmlPullParserException { + TypedArray sa = null; + String packageName = parsingPackage.getPackageName(); + ParsedPermission result = new ParsedPermission(); + + try { + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionTree); + + String name = sa.getNonConfigurationString( + R.styleable.AndroidManifestPermissionTree_name, 0); + if (name == null) { + outError[0] = "<permission-tree> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<permission-tree> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestPermissionTree_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionTree_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + } finally { + if (sa != null) { + sa.recycle(); + } + } + + int index = result.getName().indexOf('.'); + if (index > 0) { + index = result.getName().indexOf('.', index + 1); + } + if (index < 0) { + outError[0] = + "<permission-tree> name has less than three segments: " + result.getName(); + return null; + } + + result.descriptionRes = 0; + result.requestRes = 0; + result.protectionLevel = PermissionInfo.PROTECTION_NORMAL; + result.tree = true; + + boolean success = parseAllMetaData(parsingPackage, res, parser, + "<permission-tree>", result, outError); + if (!success || outError[0] != null) { + return null; + } + + return result; + } + + public static ParsedPermissionGroup parsePermissionGroup( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + String[] outError + ) throws IOException, XmlPullParserException { + TypedArray sa = null; + String packageName = parsingPackage.getPackageName(); + ParsedPermissionGroup result = new ParsedPermissionGroup(); + + try { + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionGroup); + + String name = sa.getNonConfigurationString( + R.styleable.AndroidManifestPermissionGroup_name, 0); + if (name == null) { + outError[0] = "<permission> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<permission> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestPermissionGroup_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionGroup_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + result.descriptionRes = sa.getResourceId( + R.styleable.AndroidManifestPermissionGroup_description, 0); + + result.requestDetailResourceId = sa.getResourceId( + R.styleable.AndroidManifestPermissionGroup_requestDetail, 0); + result.backgroundRequestResourceId = sa.getResourceId( + R.styleable.AndroidManifestPermissionGroup_backgroundRequest, + 0); + result.backgroundRequestDetailResourceId = sa.getResourceId( + R.styleable + .AndroidManifestPermissionGroup_backgroundRequestDetail, 0); + + result.requestRes = sa.getResourceId( + R.styleable.AndroidManifestPermissionGroup_request, 0); + result.flags = sa.getInt( + R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, + 0); + result.priority = sa.getInt( + R.styleable.AndroidManifestPermissionGroup_priority, 0); + + } finally { + if (sa != null) { + sa.recycle(); + } + } + + boolean success = parseAllMetaData(parsingPackage, res, parser, + "<permission-group>", result, outError); + if (!success || outError[0] != null) { + return null; + } + + return result; + } + + public static ParsedInstrumentation parseInstrumentation( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + String[] outError + ) throws IOException, XmlPullParserException { + TypedArray sa = null; + String packageName = parsingPackage.getPackageName(); + ParsedInstrumentation result = new ParsedInstrumentation(); + + try { + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestInstrumentation); + + // TODO(b/135203078): Re-share all of the configuration for this. ParseComponentArgs was + // un-used for this, but can be adjusted and re-added to share all the initial result + // parsing for icon/logo/name/etc in all of these parse methods. + String name = sa.getNonConfigurationString( + R.styleable.AndroidManifestInstrumentation_name, 0); + if (name == null) { + outError[0] = "<instrumentation> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<instrumentation> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestInstrumentation_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestInstrumentation_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + String str; + // Note: don't allow this value to be a reference to a resource + // that may change. + str = sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage); + result.setTargetPackage(str); + + str = sa.getNonResourceString( + R.styleable.AndroidManifestInstrumentation_targetProcesses); + result.setTargetProcesses(str); + result.handleProfiling = sa.getBoolean( + R.styleable.AndroidManifestInstrumentation_handleProfiling, false); + result.functionalTest = sa.getBoolean( + R.styleable.AndroidManifestInstrumentation_functionalTest, false); + + } finally { + if (sa != null) { + sa.recycle(); + } + } + + boolean success = parseAllMetaData(parsingPackage, res, parser, + "<instrumentation>", result, outError); + if (!success || outError[0] != null) { + return null; + } + + return result; + } + + public static ActivityInfo.WindowLayout parseLayout(Resources res, AttributeSet attrs) { + TypedArray sw = res.obtainAttributes(attrs, + R.styleable.AndroidManifestLayout); + int width = -1; + float widthFraction = -1f; + int height = -1; + float heightFraction = -1f; + final int widthType = sw.getType( + R.styleable.AndroidManifestLayout_defaultWidth); + if (widthType == TypedValue.TYPE_FRACTION) { + widthFraction = sw.getFraction( + R.styleable.AndroidManifestLayout_defaultWidth, + 1, 1, -1); + } else if (widthType == TypedValue.TYPE_DIMENSION) { + width = sw.getDimensionPixelSize( + R.styleable.AndroidManifestLayout_defaultWidth, + -1); + } + final int heightType = sw.getType( + R.styleable.AndroidManifestLayout_defaultHeight); + if (heightType == TypedValue.TYPE_FRACTION) { + heightFraction = sw.getFraction( + R.styleable.AndroidManifestLayout_defaultHeight, + 1, 1, -1); + } else if (heightType == TypedValue.TYPE_DIMENSION) { + height = sw.getDimensionPixelSize( + R.styleable.AndroidManifestLayout_defaultHeight, + -1); + } + int gravity = sw.getInt( + R.styleable.AndroidManifestLayout_gravity, + Gravity.CENTER); + int minWidth = sw.getDimensionPixelSize( + R.styleable.AndroidManifestLayout_minWidth, + -1); + int minHeight = sw.getDimensionPixelSize( + R.styleable.AndroidManifestLayout_minHeight, + -1); + sw.recycle(); + return new ActivityInfo.WindowLayout(width, widthFraction, + height, heightFraction, gravity, minWidth, minHeight); + } + + public static boolean parseIntentInfo( + ParsedIntentInfo intentInfo, + ParsingPackage parsingPackage, + Resources res, XmlResourceParser parser, boolean allowGlobs, + boolean allowAutoVerify, String[] outError + ) throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestIntentFilter); + + int priority = sa.getInt( + R.styleable.AndroidManifestIntentFilter_priority, 0); + intentInfo.setPriority(priority); + + int order = sa.getInt( + R.styleable.AndroidManifestIntentFilter_order, 0); + intentInfo.setOrder(order); + + TypedValue v = sa.peekValue( + R.styleable.AndroidManifestIntentFilter_label); + if (v != null && (intentInfo.labelRes = v.resourceId) == 0) { + intentInfo.nonLocalizedLabel = v.coerceToString(); + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0; + if (roundIconVal != 0) { + intentInfo.icon = roundIconVal; + } else { + intentInfo.icon = sa.getResourceId( + R.styleable.AndroidManifestIntentFilter_icon, 0); + } + + if (allowAutoVerify) { + intentInfo.setAutoVerify(sa.getBoolean( + R.styleable.AndroidManifestIntentFilter_autoVerify, + false)); + } + + sa.recycle(); + + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String nodeName = parser.getName(); + if (nodeName.equals("action")) { + String value = parser.getAttributeValue( + PackageParser.ANDROID_RESOURCES, "name"); + if (TextUtils.isEmpty(value)) { + outError[0] = "No value supplied for <android:name>"; + return false; + } + XmlUtils.skipCurrentTag(parser); + + intentInfo.addAction(value); + } else if (nodeName.equals("category")) { + String value = parser.getAttributeValue( + PackageParser.ANDROID_RESOURCES, "name"); + if (TextUtils.isEmpty(value)) { + outError[0] = "No value supplied for <android:name>"; + return false; + } + XmlUtils.skipCurrentTag(parser); + + intentInfo.addCategory(value); + + } else if (nodeName.equals("data")) { + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestData); + + String str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_mimeType, 0); + if (str != null) { + try { + intentInfo.addRawDataType(str); + } catch (IntentFilter.MalformedMimeTypeException e) { + outError[0] = e.toString(); + sa.recycle(); + return false; + } + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_scheme, 0); + if (str != null) { + intentInfo.addDataScheme(str); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_ssp, 0); + if (str != null) { + intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_sspPrefix, 0); + if (str != null) { + intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_sspPattern, 0); + if (str != null) { + if (!allowGlobs) { + outError[0] = "sspPattern not allowed here; ssp must be literal"; + return false; + } + intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB); + } + + String host = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_host, 0); + String port = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_port, 0); + if (host != null) { + intentInfo.addDataAuthority(host, port); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_path, 0); + if (str != null) { + intentInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathPrefix, 0); + if (str != null) { + intentInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathPattern, 0); + if (str != null) { + if (!allowGlobs) { + outError[0] = "pathPattern not allowed here; path must be literal"; + return false; + } + intentInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathAdvancedPattern, 0); + if (str != null) { + if (!allowGlobs) { + outError[0] = "pathAdvancedPattern not allowed here; path must be literal"; + return false; + } + intentInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB); + } + + sa.recycle(); + XmlUtils.skipCurrentTag(parser); + } else if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <intent-filter>: " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + } else { + outError[0] = "Bad element under <intent-filter>: " + parser.getName(); + return false; + } + } + + intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT); + + if (PackageParser.DEBUG_PARSER) { + final StringBuilder cats = new StringBuilder("Intent d="); + cats.append(intentInfo.hasDefault); + cats.append(", cat="); + + final Iterator<String> it = intentInfo.categoriesIterator(); + if (it != null) { + while (it.hasNext()) { + cats.append(' '); + cats.append(it.next()); + } + } + Slog.d(TAG, cats.toString()); + } + + return true; + } + + private static boolean parseAllMetaData( + ParsingPackage parsingPackage, + Resources res, XmlResourceParser parser, String tag, + ParsedComponent outInfo, + String[] outError + ) throws XmlPullParserException, IOException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + if (parser.getName().equals("meta-data")) { + if ((outInfo.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, + outInfo.metaData, outError)) == null) { + return false; + } + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under " + tag + ": " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + outError[0] = "Bad element under " + tag + ": " + parser.getName(); + } + } + } + + return true; + } + + public static boolean isImplicitlyExposedIntent(IntentFilter intent) { + return intent.hasCategory(Intent.CATEGORY_BROWSABLE) + || intent.hasAction(Intent.ACTION_SEND) + || intent.hasAction(Intent.ACTION_SENDTO) + || intent.hasAction(Intent.ACTION_SEND_MULTIPLE); + } +} diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java new file mode 100644 index 000000000000..0e736d522c10 --- /dev/null +++ b/core/java/android/content/pm/parsing/PackageImpl.java @@ -0,0 +1,3254 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.content.pm.parsing; + +import static android.os.Build.VERSION_CODES.DONUT; + +import static java.util.Collections.emptyMap; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.ProviderInfo; +import android.content.pm.ServiceInfo; +import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.content.res.TypedArray; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Parcel; +import android.os.UserHandle; +import android.os.storage.StorageManager; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.SparseArray; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; +import com.android.server.SystemConfig; + +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * The backing data for a package that was parsed from disk. + * + * TODO(b/135203078): Convert Lists used as sets into Sets, to better express intended use case + * TODO(b/135203078): Field nullability annotations + * TODO(b/135203078): Convert = 1 fields into Booleans + * TODO(b/135203078): Make all lists nullable and Collections.unmodifiable immutable when returned. + * Prefer add/set methods if adding is necessary. + * TODO(b/135203078): Consider comments to disable auto-format and single-line, single-space all the + * get/set methods to make this class far more compact. Maybe even separate some logic into parent + * classes, assuming there is no overhead. + * TODO(b/135203078): Copy documentation from PackageParser#Package for the relevant fields included + * here. Should clarify and clean up any differences. Also consider renames if it helps make + * things clearer. + * TODO(b/135203078): Intern all possibl e String values? Initial refactor just mirrored old + * behavior. + * + * @hide + */ +public final class PackageImpl implements ParsingPackage, ParsedPackage, AndroidPackage, + AndroidPackageWrite { + + private static final String TAG = "PackageImpl"; + + // Resource boolean are -1, so 1 means we don't know the value. + private int supportsSmallScreens = 1; + private int supportsNormalScreens = 1; + private int supportsLargeScreens = 1; + private int supportsXLargeScreens = 1; + private int resizeable = 1; + private int anyDensity = 1; + + private long[] lastPackageUsageTimeInMills = + new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT]; + + private int versionCode; + private int versionCodeMajor; + private int baseRevisionCode; + private String versionName; + + private boolean coreApp; + private int compileSdkVersion; + private String compileSdkVersionCodename; + + private String packageName; + private String realPackage; + private String manifestPackageName; + private String baseCodePath; + + private boolean requiredForAllUsers; + private String restrictedAccountType; + private String requiredAccountType; + + private boolean baseHardwareAccelerated; + + private String overlayTarget; + private String overlayTargetName; + private String overlayCategory; + private int overlayPriority; + private boolean overlayIsStatic; + private Map<String, String> overlayables = emptyMap(); + + private String staticSharedLibName; + private long staticSharedLibVersion; + private ArrayList<String> libraryNames; + private ArrayList<String> usesLibraries; + private ArrayList<String> usesOptionalLibraries; + + private ArrayList<String> usesStaticLibraries; + private long[] usesStaticLibrariesVersions; + private String[][] usesStaticLibrariesCertDigests; + + private String sharedUserId; + + private int sharedUserLabel; + private ArrayList<ConfigurationInfo> configPreferences; + private ArrayList<FeatureInfo> reqFeatures; + private ArrayList<FeatureGroupInfo> featureGroups; + + private byte[] restrictUpdateHash; + + private ArrayList<String> originalPackages; + private ArrayList<String> adoptPermissions; + + private ArrayList<String> requestedPermissions; + private ArrayList<String> implicitPermissions; + + private ArraySet<String> upgradeKeySets; + private Map<String, ArraySet<PublicKey>> keySetMapping; + + private ArrayList<String> protectedBroadcasts; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedActivity> activities; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedActivity> receivers; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedService> services; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedProvider> providers; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedPermission> permissions; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedPermissionGroup> permissionGroups; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedInstrumentation> instrumentations; + + private ArrayList<ParsedActivityIntentInfo> preferredActivityFilters; + + private Bundle appMetaData; + + private String volumeUuid; + private String applicationVolumeUuid; + private PackageParser.SigningDetails signingDetails; + + private String codePath; + + private boolean use32BitAbi; + private boolean visibleToInstantApps; + + private String cpuAbiOverride; + + private boolean isStub; + + // TODO(b/135203078): Remove, should be unused + private int preferredOrder; + + private boolean forceQueryable; + + @Nullable + private ArrayList<Intent> queriesIntents; + + @Nullable + private ArrayList<String> queriesPackages; + + private String[] splitClassLoaderNames; + private String[] splitCodePaths; + private SparseArray<int[]> splitDependencies; + private int[] splitFlags; + private String[] splitNames; + private int[] splitRevisionCodes; + + // TODO(b/135203078): Audit applicationInfo.something usages, which may be different from + // package.something usages. There were differing cases of package.field = versus + // package.appInfo.field =. This class assumes some obvious ones, like packageName, + // were collapsible, but kept the following separate. + + private String applicationInfoBaseResourcePath; + private String applicationInfoCodePath; + private String applicationInfoResourcePath; + private String[] applicationInfoSplitResourcePaths; + + private String appComponentFactory; + private String backupAgentName; + private int banner; + private int category; + private String classLoaderName; + private String className; + private int compatibleWidthLimitDp; + private String credentialProtectedDataDir; + private String dataDir; + private int descriptionRes; + private String deviceProtectedDataDir; + private boolean enabled; + private int flags; + private int fullBackupContent; + private boolean hiddenUntilInstalled; + private int icon; + private int iconRes; + private int installLocation = PackageParser.PARSE_DEFAULT_INSTALL_LOCATION; + private int labelRes; + private int largestWidthLimitDp; + private int logo; + private String manageSpaceActivityName; + private float maxAspectRatio; + private float minAspectRatio; + private int minSdkVersion; + private String name; + private String nativeLibraryDir; + private String nativeLibraryRootDir; + private boolean nativeLibraryRootRequiresIsa; + private int networkSecurityConfigRes; + private CharSequence nonLocalizedLabel; + private String permission; + private String primaryCpuAbi; + private int privateFlags; + private String processName; + private int requiresSmallestWidthDp; + private int roundIconRes; + private String secondaryCpuAbi; + private String secondaryNativeLibraryDir; + private String seInfo; + private String seInfoUser; + private int targetSandboxVersion; + private int targetSdkVersion; + private String taskAffinity; + private int theme; + private int uid = -1; + private int uiOptions; + private String[] usesLibraryFiles; + private List<SharedLibraryInfo> usesLibraryInfos; + private String zygotePreloadName; + + @VisibleForTesting + public PackageImpl( + String packageName, + String baseCodePath, + TypedArray manifestArray, + boolean isCoreApp + ) { + this.packageName = TextUtils.safeIntern(packageName); + this.manifestPackageName = this.packageName; + this.baseCodePath = baseCodePath; + + this.versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0); + this.versionCodeMajor = manifestArray.getInteger( + R.styleable.AndroidManifest_versionCodeMajor, 0); + this.baseRevisionCode = manifestArray.getInteger(R.styleable.AndroidManifest_revisionCode, + 0); + setVersionName(manifestArray.getNonConfigurationString( + R.styleable.AndroidManifest_versionName, 0)); + this.coreApp = isCoreApp; + + this.compileSdkVersion = manifestArray.getInteger( + R.styleable.AndroidManifest_compileSdkVersion, 0); + setCompileSdkVersionCodename(manifestArray.getNonConfigurationString( + R.styleable.AndroidManifest_compileSdkVersionCodename, 0)); + } + + private PackageImpl(String packageName) { + this.packageName = TextUtils.safeIntern(packageName); + this.manifestPackageName = this.packageName; + } + + @VisibleForTesting + public static ParsingPackage forParsing(String packageName) { + return new PackageImpl(packageName); + } + + @VisibleForTesting + public static ParsingPackage forParsing( + String packageName, + String baseCodePath, + TypedArray manifestArray, + boolean isCoreApp) { + return new PackageImpl(packageName, baseCodePath, manifestArray, isCoreApp); + } + + /** + * Mock an unavailable {@link AndroidPackage} to use when removing a package from the system. + * This can occur if the package was installed on a storage device that has since been removed. + * Since the infrastructure uses {@link AndroidPackage}, but for this case only cares about + * volumeUuid, just fake it rather than having separate method paths. + */ + public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) { + return new PackageImpl(packageName) + .setVolumeUuid(volumeUuid) + .hideAsParsed() + .hideAsFinal(); + } + + @Override + public ParsedPackage hideAsParsed() { + return this; + } + + @Override + public AndroidPackage hideAsFinal() { + updateFlags(); + return this; + } + + @Override + @Deprecated + public AndroidPackageWrite mutate() { + return this; + } + + private void updateFlags() { + if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + this.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; + } + if (supportsNormalScreens != 0) { + this.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; + } + if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + this.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; + } + if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 + && targetSdkVersion + >= Build.VERSION_CODES.GINGERBREAD)) { + this.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; + } + if (resizeable < 0 || (resizeable > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + this.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; + } + if (anyDensity < 0 || (anyDensity > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + this.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; + } + } + + @Override + public boolean usesCompatibilityMode() { + int flags = 0; + + if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; + } + if (supportsNormalScreens != 0) { + flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; + } + if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; + } + if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 + && targetSdkVersion + >= Build.VERSION_CODES.GINGERBREAD)) { + flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; + } + if (resizeable < 0 || (resizeable > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; + } + if (anyDensity < 0 || (anyDensity > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; + } + + return targetSdkVersion < DONUT + || (flags & (ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS + | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS + | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS + | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS + | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES + | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)) == 0; + } + + @Override + public String getBaseCodePath() { + return baseCodePath; + } + + @Override + public int getTargetSdkVersion() { + return targetSdkVersion; + } + + @Override + public String getPackageName() { + return packageName; + } + + @Override + public String getProcessName() { + return processName; + } + + @Override + public String getPermission() { + return permission; + } + + @Override + public String getStaticSharedLibName() { + return staticSharedLibName; + } + + @Override + public long getStaticSharedLibVersion() { + return staticSharedLibVersion; + } + + @Override + public String getSharedUserId() { + return sharedUserId; + } + + @Override + public List<String> getRequestedPermissions() { + return requestedPermissions == null ? Collections.emptyList() : requestedPermissions; + } + + @Nullable + @Override + public List<ParsedInstrumentation> getInstrumentations() { + return instrumentations; + } + + @Override + public Map<String, ArraySet<PublicKey>> getKeySetMapping() { + return keySetMapping == null ? emptyMap() : keySetMapping; + } + + @Override + public float getMaxAspectRatio() { + return maxAspectRatio; + } + + @Override + public float getMinAspectRatio() { + return minAspectRatio; + } + + @NonNull + @Override + public List<String> getLibraryNames() { + return libraryNames == null ? Collections.emptyList() : libraryNames; + } + + @Override + public List<ParsedActivity> getActivities() { + return activities == null ? Collections.emptyList() + : activities; + } + + @Override + public Bundle getAppMetaData() { + return appMetaData; + } + + @Nullable + @Override + public List<String> getUsesLibraries() { + return usesLibraries; + } + + @Nullable + @Override + public List<String> getUsesStaticLibraries() { + return usesStaticLibraries; + } + + @Override + public boolean isBaseHardwareAccelerated() { + return baseHardwareAccelerated; + } + + @Override + public int getUiOptions() { + return uiOptions; + } + + // TODO(b/135203078): Checking flags directly can be error prone, + // consider separate interface methods? + @Override + public int getFlags() { + return flags; + } + + // TODO(b/135203078): Checking flags directly can be error prone, + // consider separate interface methods? + @Override + public int getPrivateFlags() { + return privateFlags; + } + + @Override + public String getTaskAffinity() { + return taskAffinity; + } + + @Nullable + @Override + public List<String> getOriginalPackages() { + return originalPackages; + } + + @Override + public PackageParser.SigningDetails getSigningDetails() { + return signingDetails; + } + + @Override + public String getVolumeUuid() { + return volumeUuid; + } + + @Nullable + @Override + public List<ParsedPermissionGroup> getPermissionGroups() { + return permissionGroups; + } + + @Nullable + @Override + public List<ParsedPermission> getPermissions() { + return permissions; + } + + @Override + public String getCpuAbiOverride() { + return cpuAbiOverride; + } + + @Override + public String getPrimaryCpuAbi() { + return primaryCpuAbi; + } + + @Override + public String getSecondaryCpuAbi() { + return secondaryCpuAbi; + } + + @Override + public boolean isUse32BitAbi() { + return use32BitAbi; + } + + @Override + public boolean isForceQueryable() { + return forceQueryable; + } + + @Override + public String getCodePath() { + return codePath; + } + + @Override + public String getNativeLibraryDir() { + return nativeLibraryDir; + } + + @Override + public String getNativeLibraryRootDir() { + return nativeLibraryRootDir; + } + + @Override + public boolean isNativeLibraryRootRequiresIsa() { + return nativeLibraryRootRequiresIsa; + } + + // TODO(b/135203078): Does nothing, remove? + @Override + public int getPreferredOrder() { + return preferredOrder; + } + + @Override + public long getLongVersionCode() { + return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode); + } + + @Override + public PackageImpl setIsOverlay(boolean isOverlay) { + this.privateFlags = isOverlay + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY; + return this; + } + + @Override + public PackageImpl setExternalStorage(boolean externalStorage) { + this.flags = externalStorage + ? this.flags | ApplicationInfo.FLAG_EXTERNAL_STORAGE + : this.flags & ~ApplicationInfo.FLAG_EXTERNAL_STORAGE; + return this; + } + + @Override + public PackageImpl setIsolatedSplitLoading(boolean isolatedSplitLoading) { + this.privateFlags = isolatedSplitLoading + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING; + return this; + } + + @Override + public PackageImpl sortActivities() { + Collections.sort(this.activities, (a1, a2) -> Integer.compare(a2.order, a1.order)); + return this; + } + + @Override + public PackageImpl sortReceivers() { + Collections.sort(this.receivers, (a1, a2) -> Integer.compare(a2.order, a1.order)); + return this; + } + + @Override + public PackageImpl sortServices() { + Collections.sort(this.services, (a1, a2) -> Integer.compare(a2.order, a1.order)); + return this; + } + + @Override + public PackageImpl setBaseRevisionCode(int baseRevisionCode) { + this.baseRevisionCode = baseRevisionCode; + return this; + } + + @Override + public PackageImpl setPreferredOrder(int preferredOrder) { + this.preferredOrder = preferredOrder; + return this; + } + + @Override + public PackageImpl setVersionName(String versionName) { + this.versionName = TextUtils.safeIntern(versionName); + return this; + } + + @Override + public ParsingPackage setCompileSdkVersion(int compileSdkVersion) { + this.compileSdkVersion = compileSdkVersion; + return this; + } + + @Override + public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) { + this.compileSdkVersionCodename = TextUtils.safeIntern(compileSdkVersionCodename); + return this; + } + + @Override + public PackageImpl setMaxAspectRatio(float maxAspectRatio) { + this.maxAspectRatio = maxAspectRatio; + return this; + } + + @Override + public PackageImpl setMinAspectRatio(float minAspectRatio) { + this.minAspectRatio = minAspectRatio; + return this; + } + + @Override + public PackageImpl setMinSdkVersion(int minSdkVersion) { + this.minSdkVersion = minSdkVersion; + return this; + } + + @Override + public PackageImpl setTargetSdkVersion(int targetSdkVersion) { + this.targetSdkVersion = targetSdkVersion; + return this; + } + + @Override + public PackageImpl setRealPackage(String realPackage) { + this.realPackage = realPackage; + return this; + } + + @Override + public PackageImpl addConfigPreference(ConfigurationInfo configPreference) { + this.configPreferences = ArrayUtils.add(this.configPreferences, configPreference); + return this; + } + + @Override + public PackageImpl addReqFeature(FeatureInfo reqFeature) { + this.reqFeatures = ArrayUtils.add(this.reqFeatures, reqFeature); + return this; + } + + @Override + public PackageImpl addFeatureGroup(FeatureGroupInfo featureGroup) { + this.featureGroups = ArrayUtils.add(this.featureGroups, featureGroup); + return this; + } + + @Override + public PackageImpl addProtectedBroadcast(String protectedBroadcast) { + if (this.protectedBroadcasts == null + || !this.protectedBroadcasts.contains(protectedBroadcast)) { + this.protectedBroadcasts = ArrayUtils.add(this.protectedBroadcasts, + TextUtils.safeIntern(protectedBroadcast)); + } + return this; + } + + @Override + public PackageImpl addInstrumentation(ParsedInstrumentation instrumentation) { + this.instrumentations = ArrayUtils.add(this.instrumentations, instrumentation); + return this; + } + + @Override + public PackageImpl addOriginalPackage(String originalPackage) { + this.originalPackages = ArrayUtils.add(this.originalPackages, originalPackage); + return this; + } + + @Override + public ParsingPackage addOverlayable(String overlayableName, String actorName) { + this.overlayables = CollectionUtils.add(this.overlayables, + TextUtils.safeIntern(overlayableName), TextUtils.safeIntern(actorName)); + return this; + } + + @Override + public PackageImpl addAdoptPermission(String adoptPermission) { + this.adoptPermissions = ArrayUtils.add(this.adoptPermissions, adoptPermission); + return this; + } + + @Override + public PackageImpl addPermission(ParsedPermission permission) { + this.permissions = ArrayUtils.add(this.permissions, permission); + return this; + } + + @Override + public PackageImpl removePermission(int index) { + this.permissions.remove(index); + return this; + } + + @Override + public PackageImpl addPermissionGroup(ParsedPermissionGroup permissionGroup) { + this.permissionGroups = ArrayUtils.add(this.permissionGroups, permissionGroup); + return this; + } + + @Override + public PackageImpl addRequestedPermission(String permission) { + this.requestedPermissions = ArrayUtils.add(this.requestedPermissions, + TextUtils.safeIntern(permission)); + return this; + } + + @Override + public PackageImpl addImplicitPermission(String permission) { + this.implicitPermissions = ArrayUtils.add(this.implicitPermissions, + TextUtils.safeIntern(permission)); + return this; + } + + @Override + public PackageImpl addKeySet(String keySetName, PublicKey publicKey) { + if (keySetMapping == null) { + keySetMapping = new ArrayMap<>(); + } + + ArraySet<PublicKey> publicKeys = keySetMapping.get(keySetName); + if (publicKeys == null) { + publicKeys = new ArraySet<>(); + keySetMapping.put(keySetName, publicKeys); + } + + publicKeys.add(publicKey); + + return this; + } + + @Override + public ParsingPackage addActivity(ParsedActivity parsedActivity) { + this.activities = ArrayUtils.add(this.activities, parsedActivity); + return this; + } + + @Override + public ParsingPackage addReceiver(ParsedActivity parsedReceiver) { + this.receivers = ArrayUtils.add(this.receivers, parsedReceiver); + return this; + } + + @Override + public ParsingPackage addService(ParsedService parsedService) { + this.services = ArrayUtils.add(this.services, parsedService); + return this; + } + + @Override + public ParsingPackage addProvider(ParsedProvider parsedProvider) { + this.providers = ArrayUtils.add(this.providers, parsedProvider); + return this; + } + + @Override + public PackageImpl addLibraryName(String libraryName) { + this.libraryNames = ArrayUtils.add(this.libraryNames, TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public PackageImpl addUsesLibrary(String libraryName) { + this.usesLibraries = ArrayUtils.add(this.usesLibraries, TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public PackageImpl addUsesOptionalLibrary(String libraryName) { + this.usesOptionalLibraries = ArrayUtils.add(this.usesOptionalLibraries, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public PackageImpl removeUsesOptionalLibrary(String libraryName) { + this.usesOptionalLibraries = ArrayUtils.remove(this.usesOptionalLibraries, libraryName); + return this; + } + + @Override + public PackageImpl addUsesStaticLibrary(String libraryName) { + this.usesStaticLibraries = ArrayUtils.add(this.usesStaticLibraries, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public PackageImpl addUsesStaticLibraryVersion(long version) { + this.usesStaticLibrariesVersions = ArrayUtils.appendLong(this.usesStaticLibrariesVersions, + version, true); + return this; + } + + @Override + public PackageImpl addUsesStaticLibraryCertDigests(String[] certSha256Digests) { + this.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class, + this.usesStaticLibrariesCertDigests, certSha256Digests, true); + return this; + } + + @Override + public PackageImpl addPreferredActivityFilter( + ParsedActivityIntentInfo parsedActivityIntentInfo) { + this.preferredActivityFilters = ArrayUtils.add(this.preferredActivityFilters, + parsedActivityIntentInfo); + return this; + } + + @Override + public PackageImpl addQueriesIntent(Intent intent) { + this.queriesIntents = ArrayUtils.add(this.queriesIntents, intent); + return this; + } + + @Override + public PackageImpl addQueriesPackage(String packageName) { + this.queriesPackages = ArrayUtils.add(this.queriesPackages, + TextUtils.safeIntern(packageName)); + return this; + } + + @Override + public PackageImpl setSupportsSmallScreens(int supportsSmallScreens) { + if (supportsSmallScreens == 1) { + return this; + } + + this.supportsSmallScreens = supportsSmallScreens; + return this; + } + + @Override + public PackageImpl setSupportsNormalScreens(int supportsNormalScreens) { + if (supportsNormalScreens == 1) { + return this; + } + + this.supportsNormalScreens = supportsNormalScreens; + return this; + } + + @Override + public PackageImpl setSupportsLargeScreens(int supportsLargeScreens) { + if (supportsLargeScreens == 1) { + return this; + } + + this.supportsLargeScreens = supportsLargeScreens; + return this; + } + + @Override + public PackageImpl setSupportsXLargeScreens(int supportsXLargeScreens) { + if (supportsXLargeScreens == 1) { + return this; + } + + this.supportsXLargeScreens = supportsXLargeScreens; + return this; + } + + @Override + public PackageImpl setResizeable(int resizeable) { + if (resizeable == 1) { + return this; + } + + this.resizeable = resizeable; + return this; + } + + @Override + public PackageImpl setAnyDensity(int anyDensity) { + if (anyDensity == 1) { + return this; + } + + this.anyDensity = anyDensity; + return this; + } + + @Override + public PackageImpl setRequiresSmallestWidthDp(int requiresSmallestWidthDp) { + this.requiresSmallestWidthDp = requiresSmallestWidthDp; + return this; + } + + @Override + public PackageImpl setCompatibleWidthLimitDp(int compatibleWidthLimitDp) { + this.compatibleWidthLimitDp = compatibleWidthLimitDp; + return this; + } + + @Override + public PackageImpl setLargestWidthLimitDp(int largestWidthLimitDp) { + this.largestWidthLimitDp = largestWidthLimitDp; + return this; + } + + @Override + public PackageImpl setInstallLocation(int installLocation) { + this.installLocation = installLocation; + return this; + } + + @Override + public PackageImpl setTargetSandboxVersion(int targetSandboxVersion) { + this.targetSandboxVersion = targetSandboxVersion; + return this; + } + + @Override + public PackageImpl setRequiredForAllUsers(boolean requiredForAllUsers) { + this.requiredForAllUsers = requiredForAllUsers; + return this; + } + + @Override + public PackageImpl setRestrictedAccountType(String restrictedAccountType) { + this.restrictedAccountType = restrictedAccountType; + return this; + } + + @Override + public PackageImpl setRequiredAccountType(String requiredAccountType) { + this.requiredAccountType = requiredAccountType; + return this; + } + + @Override + public PackageImpl setBaseHardwareAccelerated(boolean baseHardwareAccelerated) { + this.baseHardwareAccelerated = baseHardwareAccelerated; + + this.flags = baseHardwareAccelerated + ? this.flags | ApplicationInfo.FLAG_HARDWARE_ACCELERATED + : this.flags & ~ApplicationInfo.FLAG_HARDWARE_ACCELERATED; + + return this; + } + + @Override + public PackageImpl setHasDomainUrls(boolean hasDomainUrls) { + this.privateFlags = hasDomainUrls + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS; + return this; + } + + @Override + public PackageImpl setAppMetaData(Bundle appMetaData) { + this.appMetaData = appMetaData; + return this; + } + + @Override + public PackageImpl setOverlayTarget(String overlayTarget) { + this.overlayTarget = overlayTarget; + return this; + } + + @Override + public PackageImpl setOverlayTargetName(String overlayTargetName) { + this.overlayTargetName = overlayTargetName; + return this; + } + + @Override + public PackageImpl setOverlayCategory(String overlayCategory) { + this.overlayCategory = overlayCategory; + return this; + } + + @Override + public PackageImpl setOverlayPriority(int overlayPriority) { + this.overlayPriority = overlayPriority; + return this; + } + + @Override + public PackageImpl setOverlayIsStatic(boolean overlayIsStatic) { + this.overlayIsStatic = overlayIsStatic; + return this; + } + + @Override + public PackageImpl setStaticSharedLibName(String staticSharedLibName) { + this.staticSharedLibName = TextUtils.safeIntern(staticSharedLibName); + return this; + } + + @Override + public PackageImpl setStaticSharedLibVersion(long staticSharedLibVersion) { + this.staticSharedLibVersion = staticSharedLibVersion; + return this; + } + + @Override + public PackageImpl setSharedUserId(String sharedUserId) { + this.sharedUserId = TextUtils.safeIntern(sharedUserId); + return this; + } + + @Override + public PackageImpl setSharedUserLabel(int sharedUserLabel) { + this.sharedUserLabel = sharedUserLabel; + return this; + } + + @Override + public PackageImpl setRestrictUpdateHash(byte[] restrictUpdateHash) { + this.restrictUpdateHash = restrictUpdateHash; + return this; + } + + @Override + public PackageImpl setUpgradeKeySets(ArraySet<String> upgradeKeySets) { + this.upgradeKeySets = upgradeKeySets; + return this; + } + + @Override + public PackageImpl setVolumeUuid(String volumeUuid) { + this.volumeUuid = volumeUuid; + return this; + } + + @Deprecated + @Override + public PackageImpl setApplicationVolumeUuid(String applicationVolumeUuid) { + this.applicationVolumeUuid = applicationVolumeUuid; + return this; + } + + @Override + public PackageImpl setSigningDetails(PackageParser.SigningDetails signingDetails) { + this.signingDetails = signingDetails; + return this; + } + + @Override + public PackageImpl setCodePath(String codePath) { + this.codePath = codePath; + return this; + } + + @Override + public PackageImpl setUse32BitAbi(boolean use32BitAbi) { + this.use32BitAbi = use32BitAbi; + return this; + } + + @Override + public PackageImpl setCpuAbiOverride(String cpuAbiOverride) { + this.cpuAbiOverride = cpuAbiOverride; + return this; + } + + @Override + public PackageImpl setForceQueryable(boolean forceQueryable) { + this.forceQueryable = forceQueryable; + return this; + } + + // TODO(b/135203078): Remove and move PackageManagerService#renameStaticSharedLibraryPackage + // into initial package parsing + @Override + public PackageImpl setPackageName(String packageName) { + this.packageName = packageName.intern(); + + if (permissions != null) { + for (ParsedPermission permission : permissions) { + permission.setPackageName(this.packageName); + } + } + + if (permissionGroups != null) { + for (ParsedPermissionGroup permissionGroup : permissionGroups) { + permissionGroup.setPackageName(this.packageName); + } + } + + if (activities != null) { + for (ParsedActivity parsedActivity : activities) { + parsedActivity.setPackageName(this.packageName); + } + } + + if (receivers != null) { + for (ParsedActivity receiver : receivers) { + receiver.setPackageName(this.packageName); + } + } + + if (providers != null) { + for (ParsedProvider provider : providers) { + provider.setPackageName(this.packageName); + } + } + + if (services != null) { + for (ParsedService service : services) { + service.setPackageName(this.packageName); + } + } + + if (instrumentations != null) { + for (ParsedInstrumentation instrumentation : instrumentations) { + instrumentation.setPackageName(this.packageName); + } + } + + return this; + } + + // Under this is parseBaseApplication + + @Override + public PackageImpl setAllowBackup(boolean allowBackup) { + this.flags = allowBackup + ? this.flags | ApplicationInfo.FLAG_ALLOW_BACKUP + : this.flags & ~ApplicationInfo.FLAG_ALLOW_BACKUP; + return this; + } + + @Override + public PackageImpl setKillAfterRestore(boolean killAfterRestore) { + this.flags = killAfterRestore + ? this.flags | ApplicationInfo.FLAG_KILL_AFTER_RESTORE + : this.flags & ~ApplicationInfo.FLAG_KILL_AFTER_RESTORE; + return this; + } + + @Override + public PackageImpl setRestoreAnyVersion(boolean restoreAnyVersion) { + this.flags = restoreAnyVersion + ? this.flags | ApplicationInfo.FLAG_RESTORE_ANY_VERSION + : this.flags & ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION; + return this; + } + + @Override + public PackageImpl setFullBackupOnly(boolean fullBackupOnly) { + this.flags = fullBackupOnly + ? this.flags | ApplicationInfo.FLAG_FULL_BACKUP_ONLY + : this.flags & ~ApplicationInfo.FLAG_FULL_BACKUP_ONLY; + return this; + } + + @Override + public PackageImpl setPersistent(boolean persistent) { + this.flags = persistent + ? this.flags | ApplicationInfo.FLAG_PERSISTENT + : this.flags & ~ApplicationInfo.FLAG_PERSISTENT; + return this; + } + + @Override + public PackageImpl setDebuggable(boolean debuggable) { + this.flags = debuggable + ? this.flags | ApplicationInfo.FLAG_DEBUGGABLE + : this.flags & ~ApplicationInfo.FLAG_DEBUGGABLE; + return this; + } + + @Override + public PackageImpl setProfileableByShell(boolean profileableByShell) { + this.privateFlags = profileableByShell + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL; + return this; + } + + @Override + public PackageImpl setVmSafeMode(boolean vmSafeMode) { + this.flags = vmSafeMode + ? this.flags | ApplicationInfo.FLAG_VM_SAFE_MODE + : this.flags & ~ApplicationInfo.FLAG_VM_SAFE_MODE; + return this; + } + + @Override + public PackageImpl setHasCode(boolean hasCode) { + this.flags = hasCode + ? this.flags | ApplicationInfo.FLAG_HAS_CODE + : this.flags & ~ApplicationInfo.FLAG_HAS_CODE; + return this; + } + + @Override + public PackageImpl setAllowTaskReparenting(boolean allowTaskReparenting) { + this.flags = allowTaskReparenting + ? this.flags | ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING + : this.flags & ~ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING; + return this; + } + + @Override + public PackageImpl setAllowClearUserData(boolean allowClearUserData) { + this.flags = allowClearUserData + ? this.flags | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA + : this.flags & ~ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; + return this; + } + + @Override + public PackageImpl setLargeHeap(boolean largeHeap) { + this.flags = largeHeap + ? this.flags | ApplicationInfo.FLAG_LARGE_HEAP + : this.flags & ~ApplicationInfo.FLAG_LARGE_HEAP; + return this; + } + + @Override + public PackageImpl setUsesCleartextTraffic(boolean usesCleartextTraffic) { + this.flags = usesCleartextTraffic + ? this.flags | ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC + : this.flags & ~ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC; + return this; + } + + @Override + public PackageImpl setSupportsRtl(boolean supportsRtl) { + this.flags = supportsRtl + ? this.flags | ApplicationInfo.FLAG_SUPPORTS_RTL + : this.flags & ~ApplicationInfo.FLAG_SUPPORTS_RTL; + return this; + } + + @Override + public PackageImpl setTestOnly(boolean testOnly) { + this.flags = testOnly + ? this.flags | ApplicationInfo.FLAG_TEST_ONLY + : this.flags & ~ApplicationInfo.FLAG_TEST_ONLY; + return this; + } + + @Override + public PackageImpl setMultiArch(boolean multiArch) { + this.flags = multiArch + ? this.flags | ApplicationInfo.FLAG_MULTIARCH + : this.flags & ~ApplicationInfo.FLAG_MULTIARCH; + return this; + } + + @Override + public PackageImpl setExtractNativeLibs(boolean extractNativeLibs) { + this.flags = extractNativeLibs + ? this.flags | ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS + : this.flags & ~ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS; + return this; + } + + @Override + public PackageImpl setIsGame(boolean isGame) { + this.flags = isGame + ? this.flags | ApplicationInfo.FLAG_IS_GAME + : this.flags & ~ApplicationInfo.FLAG_IS_GAME; + return this; + } + + @Override + public PackageImpl setBackupInForeground(boolean backupInForeground) { + this.privateFlags = backupInForeground + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; + return this; + } + + @Override + public PackageImpl setUseEmbeddedDex(boolean useEmbeddedDex) { + this.privateFlags = useEmbeddedDex + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX; + return this; + } + + @Override + public PackageImpl setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage) { + this.privateFlags = defaultToDeviceProtectedStorage + ? this.privateFlags | ApplicationInfo + .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE + : this.privateFlags & ~ApplicationInfo + .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE; + return this; + } + + @Override + public PackageImpl setDirectBootAware(boolean directBootAware) { + this.privateFlags = directBootAware + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; + return this; + } + + @Override + public PackageImpl setPartiallyDirectBootAware(boolean partiallyDirectBootAware) { + this.privateFlags = partiallyDirectBootAware + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE; + return this; + } + + @Override + public PackageImpl setActivitiesResizeModeResizeableViaSdkVersion( + boolean resizeableViaSdkVersion + ) { + this.privateFlags = resizeableViaSdkVersion + ? this.privateFlags | ApplicationInfo + .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION + : this.privateFlags & ~ApplicationInfo + .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; + return this; + } + + @Override + public PackageImpl setActivitiesResizeModeResizeable(boolean resizeable) { + this.privateFlags = resizeable + ? this.privateFlags | ApplicationInfo + .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE + : this.privateFlags & ~ApplicationInfo + .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE; + + this.privateFlags = !resizeable + ? this.privateFlags | ApplicationInfo + .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE + : this.privateFlags & ~ApplicationInfo + .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE; + return this; + } + + @Override + public PackageImpl setAllowClearUserDataOnFailedRestore( + boolean allowClearUserDataOnFailedRestore + ) { + this.privateFlags = allowClearUserDataOnFailedRestore + ? this.privateFlags | ApplicationInfo + .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE + : this.privateFlags & ~ApplicationInfo + .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE; + return this; + } + + @Override + public PackageImpl setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture) { + this.privateFlags = allowAudioPlaybackCapture + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE; + return this; + } + + @Override + public PackageImpl setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage) { + this.privateFlags = requestLegacyExternalStorage + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE; + return this; + } + + @Override + public PackageImpl setUsesNonSdkApi(boolean usesNonSdkApi) { + this.privateFlags = usesNonSdkApi + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API; + return this; + } + + @Override + public PackageImpl setHasFragileUserData(boolean hasFragileUserData) { + this.privateFlags = hasFragileUserData + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA; + return this; + } + + @Override + public PackageImpl setCantSaveState(boolean cantSaveState) { + this.privateFlags = cantSaveState + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE; + return this; + } + + @Override + public boolean cantSaveState() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0; + } + + @Override + public boolean isLibrary() { + return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames); + } + + // TODO(b/135203078): This does nothing until the final stage without applyPolicy being + // part of PackageParser + @Override + public boolean isSystemApp() { + return (flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } + + // TODO(b/135203078): This does nothing until the final stage without applyPolicy being + // part of PackageParser + @Override + public boolean isSystemExt() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0; + } + + // TODO(b/135203078): This does nothing until the final stage without applyPolicy being + // part of PackageParser + @Override + public boolean isUpdatedSystemApp() { + return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; + } + + @Override + public PackageImpl setStaticSharedLibrary(boolean staticSharedLibrary) { + this.privateFlags = staticSharedLibrary + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY; + return this; + } + + @Override + public boolean isStaticSharedLibrary() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY) != 0; + } + + @Override + public PackageImpl setVisibleToInstantApps(boolean visibleToInstantApps) { + this.visibleToInstantApps = visibleToInstantApps; + return this; + } + + @Override + public PackageImpl setIconRes(int iconRes) { + this.iconRes = iconRes; + return this; + } + + @Override + public PackageImpl setRoundIconRes(int roundIconRes) { + this.roundIconRes = roundIconRes; + return this; + } + + @Override + public PackageImpl setClassName(String className) { + this.className = className; + return this; + } + + @Override + public PackageImpl setManageSpaceActivityName(String manageSpaceActivityName) { + this.manageSpaceActivityName = manageSpaceActivityName; + return this; + } + + @Override + public PackageImpl setBackupAgentName(String backupAgentName) { + this.backupAgentName = backupAgentName; + return this; + } + + @Override + public PackageImpl setFullBackupContent(int fullBackupContent) { + this.fullBackupContent = fullBackupContent; + return this; + } + + @Override + public PackageImpl setTheme(int theme) { + this.theme = theme; + return this; + } + + @Override + public PackageImpl setDescriptionRes(int descriptionRes) { + this.descriptionRes = descriptionRes; + return this; + } + + @Override + public PackageImpl setNetworkSecurityConfigRes(int networkSecurityConfigRes) { + this.networkSecurityConfigRes = networkSecurityConfigRes; + return this; + } + + @Override + public PackageImpl setCategory(int category) { + this.category = category; + return this; + } + + @Override + public PackageImpl setPermission(String permission) { + this.permission = permission; + return this; + } + + @Override + public PackageImpl setTaskAffinity(String taskAffinity) { + this.taskAffinity = taskAffinity; + return this; + } + + @Override + public PackageImpl setAppComponentFactory(String appComponentFactory) { + this.appComponentFactory = appComponentFactory; + return this; + } + + @Override + public PackageImpl setProcessName(String processName) { + if (processName == null) { + this.processName = packageName; + } else { + this.processName = processName; + } + return this; + } + + @Override + public PackageImpl setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + @Override + public PackageImpl setUiOptions(int uiOptions) { + this.uiOptions = uiOptions; + return this; + } + + @Override + public PackageImpl setClassLoaderName(String classLoaderName) { + this.classLoaderName = classLoaderName; + return this; + } + + @Override + public PackageImpl setZygotePreloadName(String zygotePreloadName) { + this.zygotePreloadName = zygotePreloadName; + return this; + } + + // parsePackageItemInfo + + @Override + public String getName() { + return name; + } + + @Override + public PackageImpl setName(String name) { + this.name = name; + return this; + } + + @Override + public PackageImpl setIcon(int icon) { + this.icon = icon; + return this; + } + + @Override + public PackageImpl setNonLocalizedLabel(CharSequence nonLocalizedLabel) { + this.nonLocalizedLabel = nonLocalizedLabel; + return this; + } + + @Override + public PackageImpl setLogo(int logo) { + this.logo = logo; + return this; + } + + @Override + public PackageImpl setBanner(int banner) { + this.banner = banner; + return this; + } + + @Override + public PackageImpl setLabelRes(int labelRes) { + this.labelRes = labelRes; + return this; + } + + @Override + public PackageImpl asSplit( + String[] splitNames, + String[] splitCodePaths, + int[] splitRevisionCodes, + SparseArray<int[]> splitDependencies + ) { + this.splitNames = splitNames; + + if (this.splitNames != null) { + for (int index = 0; index < this.splitNames.length; index++) { + splitNames[index] = TextUtils.safeIntern(splitNames[index]); + } + } + + this.splitCodePaths = splitCodePaths; + this.splitRevisionCodes = splitRevisionCodes; + this.splitDependencies = splitDependencies; + + int count = splitNames.length; + this.splitFlags = new int[count]; + this.splitClassLoaderNames = new String[count]; + return this; + } + + @Override + public String[] getSplitNames() { + return splitNames; + } + + @Override + public String[] getSplitCodePaths() { + return splitCodePaths; + } + + @Override + public PackageImpl setSplitHasCode(int splitIndex, boolean splitHasCode) { + this.splitFlags[splitIndex] = splitHasCode + ? this.splitFlags[splitIndex] | ApplicationInfo.FLAG_HAS_CODE + : this.splitFlags[splitIndex] & ~ApplicationInfo.FLAG_HAS_CODE; + return this; + } + + @Override + public PackageImpl setSplitClassLoaderName(int splitIndex, String classLoaderName) { + this.splitClassLoaderNames[splitIndex] = classLoaderName; + return this; + } + + @Override + public List<String> makeListAllCodePaths() { + ArrayList<String> paths = new ArrayList<>(); + paths.add(baseCodePath); + + if (!ArrayUtils.isEmpty(splitCodePaths)) { + Collections.addAll(paths, splitCodePaths); + } + return paths; + } + + @Override + public PackageImpl setBaseCodePath(String baseCodePath) { + this.baseCodePath = baseCodePath; + return this; + } + + @Override + public PackageImpl setSplitCodePaths(String[] splitCodePaths) { + this.splitCodePaths = splitCodePaths; + return this; + } + + @Override + public String toString() { + return "Package{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + packageName + "}"; + } + + @Override + public PackageImpl setPrimaryCpuAbi(String primaryCpuAbi) { + this.primaryCpuAbi = primaryCpuAbi; + return this; + } + + @Override + public PackageImpl setSecondaryCpuAbi(String secondaryCpuAbi) { + this.secondaryCpuAbi = secondaryCpuAbi; + return this; + } + + @Override + public PackageImpl setNativeLibraryRootDir(String nativeLibraryRootDir) { + this.nativeLibraryRootDir = nativeLibraryRootDir; + return this; + } + + @Override + public PackageImpl setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa) { + this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; + return this; + } + + @Override + public PackageImpl setNativeLibraryDir(String nativeLibraryDir) { + this.nativeLibraryDir = nativeLibraryDir; + return this; + } + + @Override + public PackageImpl setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir) { + this.secondaryNativeLibraryDir = secondaryNativeLibraryDir; + return this; + } + + @Deprecated + @Override + public PackageImpl setApplicationInfoCodePath(String applicationInfoCodePath) { + this.applicationInfoCodePath = applicationInfoCodePath; + return this; + } + + @Deprecated + @Override + public PackageImpl setApplicationInfoResourcePath(String applicationInfoResourcePath) { + this.applicationInfoResourcePath = applicationInfoResourcePath; + return this; + } + + @Deprecated + @Override + public PackageImpl setApplicationInfoBaseResourcePath( + String applicationInfoBaseResourcePath) { + this.applicationInfoBaseResourcePath = applicationInfoBaseResourcePath; + return this; + } + + @Deprecated + @Override + public PackageImpl setApplicationInfoSplitResourcePaths( + String[] applicationInfoSplitResourcePaths) { + this.applicationInfoSplitResourcePaths = applicationInfoSplitResourcePaths; + return this; + } + + @Override + public boolean isDirectBootAware() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) != 0; + } + + @Override + public PackageImpl setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware) { + if (activities != null) { + for (ParsedActivity parsedActivity : activities) { + parsedActivity.directBootAware = allComponentsDirectBootAware; + } + } + + if (receivers != null) { + for (ParsedActivity parsedReceiver : receivers) { + parsedReceiver.directBootAware = allComponentsDirectBootAware; + } + } + + if (providers != null) { + for (ParsedProvider parsedProvider : providers) { + parsedProvider.directBootAware = allComponentsDirectBootAware; + } + } + + if (services != null) { + for (ParsedService parsedService : services) { + parsedService.directBootAware = allComponentsDirectBootAware; + } + } + + return this; + } + + @Override + public PackageImpl setSystem(boolean system) { + this.flags = system + ? this.flags | ApplicationInfo.FLAG_SYSTEM + : this.flags & ~ApplicationInfo.FLAG_SYSTEM; + return this; + } + + @Override + public PackageImpl setSystemExt(boolean systemExt) { + this.privateFlags = systemExt + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT; + return this; + } + + @Override + public PackageImpl setIsStub(boolean isStub) { + this.isStub = isStub; + return this; + } + + @Override + public PackageImpl setCoreApp(boolean coreApp) { + this.coreApp = coreApp; + return this; + } + + @Override + public ParsedPackage capPermissionPriorities() { + if (permissionGroups != null && !permissionGroups.isEmpty()) { + for (int i = permissionGroups.size() - 1; i >= 0; --i) { + // TODO(b/135203078): Builder/immutability + permissionGroups.get(i).priority = 0; + } + } + return this; + } + + @Override + public ParsedPackage clearProtectedBroadcasts() { + if (protectedBroadcasts != null) { + protectedBroadcasts.clear(); + } + return this; + } + + @Override + public ParsedPackage markNotActivitiesAsNotExportedIfSingleUser() { + // ignore export request for single user receivers + if (receivers != null) { + for (ParsedActivity receiver : receivers) { + if ((receiver.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) { + receiver.exported = false; + } + } + } + // ignore export request for single user services + if (services != null) { + for (ParsedService service : services) { + if ((service.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) { + service.exported = false; + } + } + } + // ignore export request for single user providers + if (providers != null) { + for (ParsedProvider provider : providers) { + if ((provider.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) { + provider.exported = false; + } + } + } + + return this; + } + + @Override + public ParsedPackage setPrivileged(boolean privileged) { + this.privateFlags = privileged + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRIVILEGED + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; + return this; + } + + @Override + public ParsedPackage setOem(boolean oem) { + this.privateFlags = oem + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_OEM + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_OEM; + return this; + } + + @Override + public ParsedPackage setVendor(boolean vendor) { + this.privateFlags = vendor + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_VENDOR + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_VENDOR; + return this; + } + + @Override + public ParsedPackage setProduct(boolean product) { + this.privateFlags = product + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRODUCT + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRODUCT; + return this; + } + + @Override + public ParsedPackage setOdm(boolean odm) { + this.privateFlags = odm + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ODM + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ODM; + return this; + } + + @Override + public ParsedPackage setSignedWithPlatformKey(boolean signedWithPlatformKey) { + this.privateFlags = signedWithPlatformKey + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY; + return this; + } + + @Override + public ParsedPackage clearOriginalPackages() { + if (originalPackages != null) { + originalPackages.clear(); + } + return this; + } + + @Override + public ParsedPackage clearAdoptPermissions() { + if (adoptPermissions != null) { + adoptPermissions.clear(); + } + return this; + } + + @Override + public PackageImpl addUsesLibrary(int index, String libraryName) { + this.usesLibraries = ArrayUtils.add(usesLibraries, index, libraryName); + return this; + } + + @Override + public ParsedPackage removeUsesLibrary(String libraryName) { + this.usesLibraries = ArrayUtils.remove(this.usesLibraries, libraryName); + return this; + } + + @Override + public PackageImpl addUsesOptionalLibrary(int index, String libraryName) { + this.usesOptionalLibraries = ArrayUtils.add(usesOptionalLibraries, index, libraryName); + return this; + } + + @Nullable + @Override + public List<String> getUsesOptionalLibraries() { + return usesOptionalLibraries; + } + + @Override + public int getVersionCode() { + return versionCode; + } + + @Nullable + @Override + public long[] getUsesStaticLibrariesVersions() { + return usesStaticLibrariesVersions; + } + + @Override + public PackageImpl setPackageSettingCallback(PackageSettingCallback packageSettingCallback) { + packageSettingCallback.setAndroidPackage(this); + return this; + } + + @Override + public PackageImpl setUpdatedSystemApp(boolean updatedSystemApp) { + this.flags = updatedSystemApp + ? this.flags | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP + : this.flags & ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + return this; + } + + @Override + public boolean isPrivileged() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; + } + + @Override + public PackageImpl setSeInfo(String seInfo) { + this.seInfo = seInfo; + return this; + } + + @Override + public PackageImpl setSeInfoUser(String seInfoUser) { + this.seInfoUser = seInfoUser; + return this; + } + + @Override + public PackageImpl initForUser(int userId) { + // TODO(b/135203078): Move this user state to some other data structure + this.uid = UserHandle.getUid(userId, UserHandle.getAppId(this.uid)); + + if ("android".equals(packageName)) { + dataDir = Environment.getDataSystemDirectory().getAbsolutePath(); + return this; + } + + deviceProtectedDataDir = Environment + .getDataUserDePackageDirectory(applicationVolumeUuid, userId, packageName) + .getAbsolutePath(); + credentialProtectedDataDir = Environment + .getDataUserCePackageDirectory(applicationVolumeUuid, userId, packageName) + .getAbsolutePath(); + + if ((privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0 + && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { + dataDir = deviceProtectedDataDir; + } else { + dataDir = credentialProtectedDataDir; + } + return this; + } + + @Override + public ParsedPackage setFactoryTest(boolean factoryTest) { + this.flags = factoryTest + ? this.flags | ApplicationInfo.FLAG_FACTORY_TEST + : this.flags & ~ApplicationInfo.FLAG_FACTORY_TEST; + return this; + } + + @Override + public String getManifestPackageName() { + return manifestPackageName; + } + + @Override + public String getRealPackage() { + return realPackage; + } + + @Override + public String getOverlayTarget() { + return overlayTarget; + } + + @Override + public String getOverlayTargetName() { + return overlayTargetName; + } + + @Override + public Map<String, String> getOverlayables() { + return overlayables; + } + + @Override + public boolean isOverlayIsStatic() { + return overlayIsStatic; + } + + @Override + public int[] getSplitFlags() { + return splitFlags; + } + + @Deprecated + @Override + public String getApplicationInfoVolumeUuid() { + return applicationVolumeUuid; + } + + @Nullable + @Override + public List<String> getProtectedBroadcasts() { + return protectedBroadcasts; + } + + @Nullable + @Override + public Set<String> getUpgradeKeySets() { + return upgradeKeySets; + } + + @Nullable + @Override + public String[][] getUsesStaticLibrariesCertDigests() { + return usesStaticLibrariesCertDigests; + } + + @Override + public int getOverlayPriority() { + return overlayPriority; + } + + @Deprecated + @Override + public String getAppInfoPackageName() { + return packageName; + } + + @Override + public UUID getStorageUuid() { + return StorageManager.convert(applicationVolumeUuid); + } + + @Override + public int getUid() { + return uid; + } + + @Override + public boolean isStub() { + return isStub; + } + + @Deprecated + @Override + public String getAppInfoCodePath() { + return applicationInfoCodePath; + } + + @Override + public boolean isSystem() { + return (flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } + + @Override + public boolean isMatch(int flags) { + if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { + return isSystem(); + } + return true; + } + + @Override + public boolean isVisibleToInstantApps() { + return visibleToInstantApps; + } + + @Override + public PackageImpl setLastPackageUsageTimeInMills(int reason, long time) { + lastPackageUsageTimeInMills[reason] = time; + return this; + } + + @Override + public List<SharedLibraryInfo> getUsesLibraryInfos() { + return usesLibraryInfos; + } + + @NonNull + @Override + public List<String> getAllCodePaths() { + return makeListAllCodePaths(); + } + + @Nullable + @Override + public String[] getUsesLibraryFiles() { + return usesLibraryFiles; + } + + @Override + public PackageImpl setUsesLibraryInfos( + @Nullable List<SharedLibraryInfo> usesLibraryInfos) { + this.usesLibraryInfos = usesLibraryInfos; + return this; + } + + @Override + public PackageImpl setUsesLibraryFiles(@Nullable String[] usesLibraryFiles) { + this.usesLibraryFiles = usesLibraryFiles; + return this; + } + + @Override + public PackageImpl setUid(int uid) { + this.uid = uid; + return this; + } + + @Override + public List<String> getAdoptPermissions() { + return adoptPermissions; + } + + @Override + public ApplicationInfo toAppInfoWithoutState() { + updateFlags(); + + ApplicationInfo appInfo = new ApplicationInfo(); + appInfo.packageName = packageName; + appInfo.flags = flags; + appInfo.privateFlags = privateFlags; + + appInfo.appComponentFactory = appComponentFactory; + appInfo.backupAgentName = backupAgentName; + appInfo.banner = banner; + appInfo.category = category; + appInfo.classLoaderName = classLoaderName; + appInfo.className = className; + appInfo.compatibleWidthLimitDp = compatibleWidthLimitDp; + appInfo.compileSdkVersion = compileSdkVersion; + appInfo.compileSdkVersionCodename = compileSdkVersionCodename; + appInfo.credentialProtectedDataDir = credentialProtectedDataDir; + appInfo.dataDir = dataDir; + appInfo.descriptionRes = descriptionRes; + appInfo.deviceProtectedDataDir = deviceProtectedDataDir; + appInfo.enabled = enabled; + appInfo.fullBackupContent = fullBackupContent; + appInfo.hiddenUntilInstalled = hiddenUntilInstalled; + appInfo.icon = icon; + appInfo.iconRes = iconRes; + appInfo.installLocation = installLocation; + appInfo.labelRes = labelRes; + appInfo.largestWidthLimitDp = largestWidthLimitDp; + appInfo.logo = logo; + appInfo.manageSpaceActivityName = manageSpaceActivityName; + appInfo.maxAspectRatio = maxAspectRatio; + appInfo.metaData = appMetaData; + appInfo.minAspectRatio = minAspectRatio; + appInfo.minSdkVersion = minSdkVersion; + appInfo.name = className; + if (appInfo.name != null) { + appInfo.name = appInfo.name.trim(); + } + appInfo.nativeLibraryDir = nativeLibraryDir; + appInfo.nativeLibraryRootDir = nativeLibraryRootDir; + appInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; + appInfo.networkSecurityConfigRes = networkSecurityConfigRes; + appInfo.nonLocalizedLabel = nonLocalizedLabel; + if (appInfo.nonLocalizedLabel != null) { + appInfo.nonLocalizedLabel = appInfo.nonLocalizedLabel.toString().trim(); + } + appInfo.packageName = packageName; + appInfo.permission = permission; + appInfo.primaryCpuAbi = primaryCpuAbi; + appInfo.processName = getProcessName(); + appInfo.requiresSmallestWidthDp = requiresSmallestWidthDp; + appInfo.roundIconRes = roundIconRes; + appInfo.secondaryCpuAbi = secondaryCpuAbi; + appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir; + appInfo.seInfo = seInfo; + appInfo.seInfoUser = seInfoUser; + appInfo.sharedLibraryFiles = usesLibraryFiles; + appInfo.sharedLibraryInfos = ArrayUtils.isEmpty(usesLibraryInfos) ? null : usesLibraryInfos; + appInfo.splitClassLoaderNames = splitClassLoaderNames; + appInfo.splitDependencies = splitDependencies; + appInfo.splitNames = splitNames; + appInfo.storageUuid = StorageManager.convert(volumeUuid); + appInfo.targetSandboxVersion = targetSandboxVersion; + appInfo.targetSdkVersion = targetSdkVersion; + appInfo.taskAffinity = taskAffinity; + appInfo.theme = theme; + appInfo.uid = uid; + appInfo.uiOptions = uiOptions; + appInfo.volumeUuid = volumeUuid; + appInfo.zygotePreloadName = zygotePreloadName; + + appInfo.setBaseCodePath(baseCodePath); + appInfo.setBaseResourcePath(baseCodePath); + appInfo.setCodePath(codePath); + appInfo.setResourcePath(codePath); + appInfo.setSplitCodePaths(splitCodePaths); + appInfo.setSplitResourcePaths(splitCodePaths); + appInfo.setVersionCode(getLongVersionCode()); + + // TODO(b/135203078): Can this be removed? Looks only used in ActivityInfo. +// appInfo.showUserIcon = pkg.getShowUserIcon(); + // TODO(b/135203078): Unused? +// appInfo.resourceDirs = pkg.getResourceDirs(); + // TODO(b/135203078): Unused? +// appInfo.enabledSetting = pkg.getEnabledSetting(); + // TODO(b/135203078): See PackageImpl#getHiddenApiEnforcementPolicy +// appInfo.mHiddenApiPolicy = pkg.getHiddenApiPolicy(); + + return appInfo; + } + + @Override + public PackageImpl setVersionCode(int versionCode) { + this.versionCode = versionCode; + return this; + } + + @Override + public PackageImpl setHiddenUntilInstalled(boolean hidden) { + this.hiddenUntilInstalled = hidden; + return this; + } + + @Override + public String getSeInfo() { + return seInfo; + } + + @Deprecated + @Override + public String getAppInfoResourcePath() { + return applicationInfoResourcePath; + } + + @Override + public boolean isForwardLocked() { + // TODO(b/135203078): Unused? Move to debug flag? + return false; + } + + @Override + public byte[] getRestrictUpdateHash() { + return restrictUpdateHash; + } + + @Override + public boolean hasComponentClassName(String className) { + if (activities != null) { + for (ParsedActivity parsedActivity : activities) { + if (Objects.equals(className, parsedActivity.className)) { + return true; + } + } + } + + if (receivers != null) { + for (ParsedActivity receiver : receivers) { + if (Objects.equals(className, receiver.className)) { + return true; + } + } + } + + if (providers != null) { + for (ParsedProvider provider : providers) { + if (Objects.equals(className, provider.className)) { + return true; + } + } + } + + if (services != null) { + for (ParsedService service : services) { + if (Objects.equals(className, service.className)) { + return true; + } + } + } + + if (instrumentations != null) { + for (ParsedInstrumentation instrumentation : instrumentations) { + if (Objects.equals(className, instrumentation.className)) { + return true; + } + } + } + + return false; + } + + @Override + public boolean isDefaultToDeviceProtectedStorage() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) + != 0; + } + + @Override + public boolean isInternal() { + return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0; + } + + @Override + public int getBaseRevisionCode() { + return baseRevisionCode; + } + + @Override + public int[] getSplitRevisionCodes() { + return splitRevisionCodes; + } + + @Override + public boolean canHaveOatDir() { + // The following app types CANNOT have oat directory + // - non-updated system apps + return !isSystem() || isUpdatedSystemApp(); + } + + @Override + public long getLatestPackageUseTimeInMills() { + long latestUse = 0L; + for (long use : lastPackageUsageTimeInMills) { + latestUse = Math.max(latestUse, use); + } + return latestUse; + } + + @Override + public long getLatestForegroundPackageUseTimeInMills() { + int[] foregroundReasons = { + PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY, + PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE + }; + + long latestUse = 0L; + for (int reason : foregroundReasons) { + latestUse = Math.max(latestUse, lastPackageUsageTimeInMills[reason]); + } + return latestUse; + } + + @Override + public boolean isCoreApp() { + return coreApp; + } + + @Override + public String getVersionName() { + return versionName; + } + + @Override + public PackageImpl setVersionCodeMajor(int versionCodeMajor) { + this.versionCodeMajor = versionCodeMajor; + return this; + } + + @Override + public long[] getLastPackageUsageTimeInMills() { + return lastPackageUsageTimeInMills; + } + + @Override + public String getDataDir() { + return dataDir; + } + + @Override + public boolean isExternal() { + return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; + } + + @Override + public List<String> getImplicitPermissions() { + return implicitPermissions == null ? Collections.emptyList() : implicitPermissions; + } + + /** + * TODO(b/135203078): Remove, ensure b/140256621 is fixed or irrelevant + * TODO(b/140256621): Remove after fixing instant app check + * @deprecated This method always returns false because there's no paired set method + */ + @Deprecated + @Override + public boolean isInstantApp() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0; + } + + @Override + public boolean hasRequestedLegacyExternalStorage() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) != 0; + } + + @Override + public boolean isVendor() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; + } + + @Override + public boolean isProduct() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; + } + + @Override + public boolean isOem() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0; + } + + @Override + public boolean isEncryptionAware() { + boolean isPartiallyDirectBootAware = + (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0; + return isDirectBootAware() || isPartiallyDirectBootAware; + } + + @Override + public boolean isEmbeddedDexUsed() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX) != 0; + } + + @Deprecated + @Override + public String getAppInfoProcessName() { + return processName; + } + + @Override + public List<String> getAllCodePathsExcludingResourceOnly() { + ArrayList<String> paths = new ArrayList<>(); + if ((flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { + paths.add(baseCodePath); + } + if (!ArrayUtils.isEmpty(splitCodePaths)) { + for (int i = 0; i < splitCodePaths.length; i++) { + if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { + paths.add(splitCodePaths[i]); + } + } + } + return paths; + } + + @Deprecated + @Override + public String getAppInfoName() { + return name; + } + + private boolean isSignedWithPlatformKey() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY) != 0; + } + + private boolean usesNonSdkApi() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API) != 0; + } + + private boolean isPackageWhitelistedForHiddenApis() { + return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName); + } + + private boolean isAllowedToUseHiddenApis() { + if (isSignedWithPlatformKey()) { + return true; + } else if (isSystemApp() || isUpdatedSystemApp()) { + return usesNonSdkApi() || isPackageWhitelistedForHiddenApis(); + } else { + return false; + } + } + + @Override + public int getHiddenApiEnforcementPolicy() { + if (isAllowedToUseHiddenApis()) { + return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED; + } + + // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done + // entirely through ApplicationInfo and shouldn't touch this specific class, but that + // may not always hold true. +// if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) { +// return mHiddenApiPolicy; +// } + return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED; + } + + @Nullable + @Override + public SparseArray<int[]> getSplitDependencies() { + return splitDependencies; + } + + @Override + public boolean requestsIsolatedSplitLoading() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING) != 0; + } + + @Deprecated + @Override + public String getAppInfoClassLoaderName() { + return classLoaderName; + } + + @Override + public String getClassLoaderName() { + return classLoaderName; + } + + @Override + public String[] getSplitClassLoaderNames() { + return splitClassLoaderNames; + } + + @Override + public String getOverlayCategory() { + return overlayCategory; + } + + @Override + public boolean isProfileableByShell() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0; + } + + @Nullable + @Override + public List<ParsedActivityIntentInfo> getPreferredActivityFilters() { + return preferredActivityFilters; + } + + @Override + public boolean isHiddenUntilInstalled() { + return hiddenUntilInstalled; + } + + @Override + public int getMinSdkVersion() { + return minSdkVersion; + } + + @Override + public String getRestrictedAccountType() { + return restrictedAccountType; + } + + @Override + public String getRequiredAccountType() { + return requiredAccountType; + } + + @Override + public int getInstallLocation() { + return installLocation; + } + + @Override + public List<ParsedActivity> getReceivers() { + return receivers; + } + + @Override + public List<ParsedService> getServices() { + return services; + } + + @Override + public List<ParsedProvider> getProviders() { + return providers; + } + + @Override + public int getSharedUserLabel() { + return sharedUserLabel; + } + + @Override + public int getVersionCodeMajor() { + return versionCodeMajor; + } + + @Override + public boolean isRequiredForAllUsers() { + return requiredForAllUsers; + } + + @Override + public int getCompileSdkVersion() { + return compileSdkVersion; + } + + @Override + public String getCompileSdkVersionCodeName() { + return compileSdkVersionCodename; + } + + @Nullable + @Override + public List<ConfigurationInfo> getConfigPreferences() { + return configPreferences; + } + + @Nullable + @Override + public List<FeatureInfo> getReqFeatures() { + return reqFeatures; + } + + @Override + public List<FeatureGroupInfo> getFeatureGroups() { + return featureGroups; + } + + @Override + public String getDeviceProtectedDataDir() { + return deviceProtectedDataDir; + } + + @Override + public String getCredentialProtectedDataDir() { + return credentialProtectedDataDir; + } + + @Override + public String getSeInfoUser() { + return seInfoUser; + } + + @Override + public String getClassName() { + return className; + } + + @Override + public int getTheme() { + return theme; + } + + @Override + public int getRequiresSmallestWidthDp() { + return requiresSmallestWidthDp; + } + + @Override + public int getCompatibleWidthLimitDp() { + return compatibleWidthLimitDp; + } + + @Override + public int getLargestWidthLimitDp() { + return largestWidthLimitDp; + } + + @Override + public String getScanSourceDir() { + return applicationInfoCodePath; + } + + @Override + public String getScanPublicSourceDir() { + return applicationInfoResourcePath; + } + + @Override + public String getPublicSourceDir() { + return applicationInfoBaseResourcePath; + } + + @Override + public String[] getSplitPublicSourceDirs() { + return applicationInfoSplitResourcePaths; + } + + @Override + public String getSecondaryNativeLibraryDir() { + return secondaryNativeLibraryDir; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public String getManageSpaceActivityName() { + return manageSpaceActivityName; + } + + @Override + public int getDescriptionRes() { + return descriptionRes; + } + + @Override + public String getBackupAgentName() { + return backupAgentName; + } + + @Override + public int getFullBackupContent() { + return fullBackupContent; + } + + @Override + public int getNetworkSecurityConfigRes() { + return networkSecurityConfigRes; + } + + @Override + public int getCategory() { + return category; + } + + @Override + public int getTargetSandboxVersion() { + return targetSandboxVersion; + } + + @Override + public String getAppComponentFactory() { + return appComponentFactory; + } + + @Override + public int getIconRes() { + return iconRes; + } + + @Override + public int getRoundIconRes() { + return roundIconRes; + } + + @Override + public String getZygotePreloadName() { + return zygotePreloadName; + } + + @Override + public int getLabelRes() { + return labelRes; + } + + @Override + public CharSequence getNonLocalizedLabel() { + return nonLocalizedLabel; + } + + @Override + public int getIcon() { + return icon; + } + + @Override + public int getBanner() { + return banner; + } + + @Override + public int getLogo() { + return logo; + } + + @Override + public Bundle getMetaData() { + return appMetaData; + } + + @Override + @Nullable + public List<Intent> getQueriesIntents() { + return queriesIntents; + } + + @Override + @Nullable + public List<String> getQueriesPackages() { + return queriesPackages; + } + + private static void internStringArrayList(List<String> list) { + if (list != null) { + final int N = list.size(); + for (int i = 0; i < N; ++i) { + list.set(i, list.get(i).intern()); + } + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(this.supportsSmallScreens); + dest.writeInt(this.supportsNormalScreens); + dest.writeInt(this.supportsLargeScreens); + dest.writeInt(this.supportsXLargeScreens); + dest.writeInt(this.resizeable); + dest.writeInt(this.anyDensity); + dest.writeLongArray(this.lastPackageUsageTimeInMills); + dest.writeInt(this.versionCode); + dest.writeInt(this.versionCodeMajor); + dest.writeInt(this.baseRevisionCode); + dest.writeString(this.versionName); + dest.writeBoolean(this.coreApp); + dest.writeInt(this.compileSdkVersion); + dest.writeString(this.compileSdkVersionCodename); + dest.writeString(this.packageName); + dest.writeString(this.realPackage); + dest.writeString(this.manifestPackageName); + dest.writeString(this.baseCodePath); + dest.writeBoolean(this.requiredForAllUsers); + dest.writeString(this.restrictedAccountType); + dest.writeString(this.requiredAccountType); + dest.writeBoolean(this.baseHardwareAccelerated); + dest.writeString(this.overlayTarget); + dest.writeString(this.overlayTargetName); + dest.writeString(this.overlayCategory); + dest.writeInt(this.overlayPriority); + dest.writeBoolean(this.overlayIsStatic); + dest.writeMap(this.overlayables); + dest.writeString(this.staticSharedLibName); + dest.writeLong(this.staticSharedLibVersion); + dest.writeStringList(this.libraryNames); + dest.writeStringList(this.usesLibraries); + dest.writeStringList(this.usesOptionalLibraries); + dest.writeStringList(this.usesStaticLibraries); + dest.writeLongArray(this.usesStaticLibrariesVersions); + + if (this.usesStaticLibrariesCertDigests == null) { + dest.writeInt(-1); + } else { + dest.writeInt(this.usesStaticLibrariesCertDigests.length); + for (int index = 0; index < this.usesStaticLibrariesCertDigests.length; index++) { + dest.writeStringArray(this.usesStaticLibrariesCertDigests[index]); + } + } + + dest.writeString(this.sharedUserId); + dest.writeInt(this.sharedUserLabel); + dest.writeTypedList(this.configPreferences); + dest.writeTypedList(this.reqFeatures); + dest.writeTypedList(this.featureGroups); + dest.writeByteArray(this.restrictUpdateHash); + dest.writeStringList(this.originalPackages); + dest.writeStringList(this.adoptPermissions); + dest.writeStringList(this.requestedPermissions); + dest.writeStringList(this.implicitPermissions); + dest.writeArraySet(this.upgradeKeySets); + dest.writeMap(this.keySetMapping); + dest.writeStringList(this.protectedBroadcasts); + dest.writeTypedList(this.activities); + dest.writeTypedList(this.receivers); + dest.writeTypedList(this.services); + dest.writeTypedList(this.providers); + dest.writeTypedList(this.permissions); + dest.writeTypedList(this.permissionGroups); + dest.writeTypedList(this.instrumentations); + ParsedIntentInfo.writeIntentsList(this.preferredActivityFilters, dest, flags); + dest.writeBundle(this.appMetaData); + dest.writeString(this.volumeUuid); + dest.writeString(this.applicationVolumeUuid); + dest.writeParcelable(this.signingDetails, flags); + dest.writeString(this.codePath); + dest.writeBoolean(this.use32BitAbi); + dest.writeBoolean(this.visibleToInstantApps); + dest.writeString(this.cpuAbiOverride); + dest.writeBoolean(this.isStub); + dest.writeInt(this.preferredOrder); + dest.writeBoolean(this.forceQueryable); + dest.writeParcelableList(this.queriesIntents, flags); + dest.writeStringList(this.queriesPackages); + dest.writeString(this.applicationInfoBaseResourcePath); + dest.writeString(this.applicationInfoCodePath); + dest.writeString(this.applicationInfoResourcePath); + dest.writeStringArray(this.applicationInfoSplitResourcePaths); + dest.writeString(this.appComponentFactory); + dest.writeString(this.backupAgentName); + dest.writeInt(this.banner); + dest.writeInt(this.category); + dest.writeString(this.classLoaderName); + dest.writeString(this.className); + dest.writeInt(this.compatibleWidthLimitDp); + dest.writeString(this.credentialProtectedDataDir); + dest.writeString(this.dataDir); + dest.writeInt(this.descriptionRes); + dest.writeString(this.deviceProtectedDataDir); + dest.writeBoolean(this.enabled); + dest.writeInt(this.flags); + dest.writeInt(this.fullBackupContent); + dest.writeBoolean(this.hiddenUntilInstalled); + dest.writeInt(this.icon); + dest.writeInt(this.iconRes); + dest.writeInt(this.installLocation); + dest.writeInt(this.labelRes); + dest.writeInt(this.largestWidthLimitDp); + dest.writeInt(this.logo); + dest.writeString(this.manageSpaceActivityName); + dest.writeFloat(this.maxAspectRatio); + dest.writeFloat(this.minAspectRatio); + dest.writeInt(this.minSdkVersion); + dest.writeString(this.name); + dest.writeString(this.nativeLibraryDir); + dest.writeString(this.nativeLibraryRootDir); + dest.writeBoolean(this.nativeLibraryRootRequiresIsa); + dest.writeInt(this.networkSecurityConfigRes); + dest.writeCharSequence(this.nonLocalizedLabel); + dest.writeString(this.permission); + dest.writeString(this.primaryCpuAbi); + dest.writeInt(this.privateFlags); + dest.writeString(this.processName); + dest.writeInt(this.requiresSmallestWidthDp); + dest.writeInt(this.roundIconRes); + dest.writeString(this.secondaryCpuAbi); + dest.writeString(this.secondaryNativeLibraryDir); + dest.writeString(this.seInfo); + dest.writeString(this.seInfoUser); + dest.writeInt(this.targetSandboxVersion); + dest.writeInt(this.targetSdkVersion); + dest.writeString(this.taskAffinity); + dest.writeInt(this.theme); + dest.writeInt(this.uid); + dest.writeInt(this.uiOptions); + dest.writeStringArray(this.usesLibraryFiles); + dest.writeTypedList(this.usesLibraryInfos); + dest.writeString(this.zygotePreloadName); + dest.writeStringArray(this.splitClassLoaderNames); + dest.writeStringArray(this.splitCodePaths); + dest.writeSparseArray(this.splitDependencies); + dest.writeIntArray(this.splitFlags); + dest.writeStringArray(this.splitNames); + dest.writeIntArray(this.splitRevisionCodes); + } + + public PackageImpl(Parcel in) { + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + this.supportsSmallScreens = in.readInt(); + this.supportsNormalScreens = in.readInt(); + this.supportsLargeScreens = in.readInt(); + this.supportsXLargeScreens = in.readInt(); + this.resizeable = in.readInt(); + this.anyDensity = in.readInt(); + this.lastPackageUsageTimeInMills = in.createLongArray(); + this.versionCode = in.readInt(); + this.versionCodeMajor = in.readInt(); + this.baseRevisionCode = in.readInt(); + this.versionName = TextUtils.safeIntern(in.readString()); + this.coreApp = in.readBoolean(); + this.compileSdkVersion = in.readInt(); + this.compileSdkVersionCodename = TextUtils.safeIntern(in.readString()); + this.packageName = TextUtils.safeIntern(in.readString()); + this.realPackage = in.readString(); + this.manifestPackageName = in.readString(); + this.baseCodePath = in.readString(); + this.requiredForAllUsers = in.readBoolean(); + this.restrictedAccountType = in.readString(); + this.requiredAccountType = in.readString(); + this.baseHardwareAccelerated = in.readBoolean(); + this.overlayTarget = in.readString(); + this.overlayTargetName = in.readString(); + this.overlayCategory = in.readString(); + this.overlayPriority = in.readInt(); + this.overlayIsStatic = in.readBoolean(); + this.overlayables = new HashMap<>(); + in.readMap(overlayables, boot); + this.staticSharedLibName = TextUtils.safeIntern(in.readString()); + this.staticSharedLibVersion = in.readLong(); + this.libraryNames = in.createStringArrayList(); + internStringArrayList(this.libraryNames); + this.usesLibraries = in.createStringArrayList(); + internStringArrayList(this.usesLibraries); + this.usesOptionalLibraries = in.createStringArrayList(); + internStringArrayList(this.usesOptionalLibraries); + this.usesStaticLibraries = in.createStringArrayList(); + internStringArrayList(usesStaticLibraries); + this.usesStaticLibrariesVersions = in.createLongArray(); + + int digestsSize = in.readInt(); + if (digestsSize >= 0) { + this.usesStaticLibrariesCertDigests = new String[digestsSize][]; + for (int index = 0; index < digestsSize; index++) { + this.usesStaticLibrariesCertDigests[index] = in.readStringArray(); + } + } + + this.sharedUserId = TextUtils.safeIntern(in.readString()); + this.sharedUserLabel = in.readInt(); + this.configPreferences = in.createTypedArrayList(ConfigurationInfo.CREATOR); + this.reqFeatures = in.createTypedArrayList(FeatureInfo.CREATOR); + this.featureGroups = in.createTypedArrayList(FeatureGroupInfo.CREATOR); + this.restrictUpdateHash = in.createByteArray(); + this.originalPackages = in.createStringArrayList(); + this.adoptPermissions = in.createStringArrayList(); + this.requestedPermissions = in.createStringArrayList(); + internStringArrayList(this.requestedPermissions); + this.implicitPermissions = in.createStringArrayList(); + internStringArrayList(this.implicitPermissions); + this.upgradeKeySets = (ArraySet<String>) in.readArraySet(boot); + this.keySetMapping = in.readHashMap(boot); + this.protectedBroadcasts = in.createStringArrayList(); + internStringArrayList(this.protectedBroadcasts); + this.activities = in.createTypedArrayList(ParsedActivity.CREATOR); + this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR); + this.services = in.createTypedArrayList(ParsedService.CREATOR); + this.providers = in.createTypedArrayList(ParsedProvider.CREATOR); + this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR); + this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR); + this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR); + this.preferredActivityFilters = ParsedIntentInfo.createIntentsList(in); + this.appMetaData = in.readBundle(boot); + this.volumeUuid = in.readString(); + this.applicationVolumeUuid = in.readString(); + this.signingDetails = in.readParcelable(boot); + this.codePath = in.readString(); + this.use32BitAbi = in.readBoolean(); + this.visibleToInstantApps = in.readBoolean(); + this.cpuAbiOverride = in.readString(); + this.isStub = in.readBoolean(); + this.preferredOrder = in.readInt(); + this.forceQueryable = in.readBoolean(); + this.queriesIntents = in.createTypedArrayList(Intent.CREATOR); + this.queriesPackages = in.createStringArrayList(); + internStringArrayList(this.queriesPackages); + this.applicationInfoBaseResourcePath = in.readString(); + this.applicationInfoCodePath = in.readString(); + this.applicationInfoResourcePath = in.readString(); + this.applicationInfoSplitResourcePaths = in.createStringArray(); + this.appComponentFactory = in.readString(); + this.backupAgentName = in.readString(); + this.banner = in.readInt(); + this.category = in.readInt(); + this.classLoaderName = in.readString(); + this.className = in.readString(); + this.compatibleWidthLimitDp = in.readInt(); + this.credentialProtectedDataDir = in.readString(); + this.dataDir = in.readString(); + this.descriptionRes = in.readInt(); + this.deviceProtectedDataDir = in.readString(); + this.enabled = in.readBoolean(); + this.flags = in.readInt(); + this.fullBackupContent = in.readInt(); + this.hiddenUntilInstalled = in.readBoolean(); + this.icon = in.readInt(); + this.iconRes = in.readInt(); + this.installLocation = in.readInt(); + this.labelRes = in.readInt(); + this.largestWidthLimitDp = in.readInt(); + this.logo = in.readInt(); + this.manageSpaceActivityName = in.readString(); + this.maxAspectRatio = in.readFloat(); + this.minAspectRatio = in.readFloat(); + this.minSdkVersion = in.readInt(); + this.name = in.readString(); + this.nativeLibraryDir = in.readString(); + this.nativeLibraryRootDir = in.readString(); + this.nativeLibraryRootRequiresIsa = in.readBoolean(); + this.networkSecurityConfigRes = in.readInt(); + this.nonLocalizedLabel = in.readCharSequence(); + this.permission = TextUtils.safeIntern(in.readString()); + this.primaryCpuAbi = in.readString(); + this.privateFlags = in.readInt(); + this.processName = in.readString(); + this.requiresSmallestWidthDp = in.readInt(); + this.roundIconRes = in.readInt(); + this.secondaryCpuAbi = in.readString(); + this.secondaryNativeLibraryDir = in.readString(); + this.seInfo = in.readString(); + this.seInfoUser = in.readString(); + this.targetSandboxVersion = in.readInt(); + this.targetSdkVersion = in.readInt(); + this.taskAffinity = in.readString(); + this.theme = in.readInt(); + this.uid = in.readInt(); + this.uiOptions = in.readInt(); + this.usesLibraryFiles = in.createStringArray(); + this.usesLibraryInfos = in.createTypedArrayList(SharedLibraryInfo.CREATOR); + this.zygotePreloadName = in.readString(); + this.splitClassLoaderNames = in.createStringArray(); + this.splitCodePaths = in.createStringArray(); + this.splitDependencies = in.readSparseArray(boot); + this.splitFlags = in.createIntArray(); + this.splitNames = in.createStringArray(); + this.splitRevisionCodes = in.createIntArray(); + } + + public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() { + @Override + public PackageImpl createFromParcel(Parcel source) { + return new PackageImpl(source); + } + + @Override + public PackageImpl[] newArray(int size) { + return new PackageImpl[size]; + } + }; +} diff --git a/core/java/android/content/pm/parsing/PackageInfoUtils.java b/core/java/android/content/pm/parsing/PackageInfoUtils.java new file mode 100644 index 000000000000..af9ba8d1ed90 --- /dev/null +++ b/core/java/android/content/pm/parsing/PackageInfoUtils.java @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing; + +import android.annotation.Nullable; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ComponentInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FallbackCategoryProvider; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.InstrumentationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PackageUserState; +import android.content.pm.PermissionGroupInfo; +import android.content.pm.PermissionInfo; +import android.content.pm.ProviderInfo; +import android.content.pm.SELinuxUtil; +import android.content.pm.ServiceInfo; +import android.content.pm.Signature; +import android.content.pm.SigningInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; + +import com.android.internal.util.ArrayUtils; + +import java.util.Set; + +/** @hide */ +public class PackageInfoUtils { + + private static final String TAG = ApkParseUtils.TAG; + + /** + * Returns true if the package is installed and not hidden, or if the caller + * explicitly wanted all uninstalled and hidden packages as well. + */ + private static boolean checkUseInstalledOrHidden(AndroidPackage pkg, PackageUserState state, + @PackageManager.PackageInfoFlags int flags) { + // Returns false if the package is hidden system app until installed. + if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0 + && !state.installed + && pkg.isHiddenUntilInstalled()) { + return false; + } + + // If available for the target user, or trying to match uninstalled packages and it's + // a system app. + return state.isAvailable(flags) + || (pkg.isSystemApp() + && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0 + || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0)); + } + + public static PackageInfo generate(AndroidPackage pkg, int[] gids, + @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, + Set<String> grantedPermissions, PackageUserState state, int userId) { + if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) { + return null; + } + ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId); + + PackageInfo pi = new PackageInfo(); + pi.packageName = pkg.getPackageName(); + pi.splitNames = pkg.getSplitNames(); + pi.versionCode = pkg.getVersionCode(); + pi.versionCodeMajor = pkg.getVersionCodeMajor(); + pi.baseRevisionCode = pkg.getBaseRevisionCode(); + pi.splitRevisionCodes = pkg.getSplitRevisionCodes(); + pi.versionName = pkg.getVersionName(); + pi.sharedUserId = pkg.getSharedUserId(); + pi.sharedUserLabel = pkg.getSharedUserLabel(); + pi.applicationInfo = applicationInfo; + pi.installLocation = pkg.getInstallLocation(); + pi.isStub = pkg.isStub(); + pi.coreApp = pkg.isCoreApp(); + if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 + || (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { + pi.requiredForAllUsers = pkg.isRequiredForAllUsers(); + } + pi.restrictedAccountType = pkg.getRestrictedAccountType(); + pi.requiredAccountType = pkg.getRequiredAccountType(); + pi.overlayTarget = pkg.getOverlayTarget(); + pi.targetOverlayableName = pkg.getOverlayTargetName(); + pi.overlayCategory = pkg.getOverlayCategory(); + pi.overlayPriority = pkg.getOverlayPriority(); + pi.mOverlayIsStatic = pkg.isOverlayIsStatic(); + pi.compileSdkVersion = pkg.getCompileSdkVersion(); + pi.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName(); + pi.firstInstallTime = firstInstallTime; + pi.lastUpdateTime = lastUpdateTime; + if ((flags & PackageManager.GET_GIDS) != 0) { + pi.gids = gids; + } + if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) { + int size = pkg.getConfigPreferences() != null ? pkg.getConfigPreferences().size() : 0; + if (size > 0) { + pi.configPreferences = new ConfigurationInfo[size]; + pkg.getConfigPreferences().toArray(pi.configPreferences); + } + size = pkg.getReqFeatures() != null ? pkg.getReqFeatures().size() : 0; + if (size > 0) { + pi.reqFeatures = new FeatureInfo[size]; + pkg.getReqFeatures().toArray(pi.reqFeatures); + } + size = pkg.getFeatureGroups() != null ? pkg.getFeatureGroups().size() : 0; + if (size > 0) { + pi.featureGroups = new FeatureGroupInfo[size]; + pkg.getFeatureGroups().toArray(pi.featureGroups); + } + } + if ((flags & PackageManager.GET_ACTIVITIES) != 0) { + if (pkg.getActivities() != null) { + final int N = pkg.getActivities().size(); + if (N > 0) { + int num = 0; + final ActivityInfo[] res = new ActivityInfo[N]; + for (int i = 0; i < N; i++) { + final ParsedActivity a = pkg.getActivities().get(i); + if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) { + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals( + a.className)) { + continue; + } + res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo, + userId); + } + } + pi.activities = ArrayUtils.trimToSize(res, num); + } + } + } + if ((flags & PackageManager.GET_RECEIVERS) != 0) { + if (pkg.getReceivers() != null) { + final int size = pkg.getReceivers().size(); + if (size > 0) { + int num = 0; + final ActivityInfo[] res = new ActivityInfo[size]; + for (int i = 0; i < size; i++) { + final ParsedActivity a = pkg.getReceivers().get(i); + if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) { + res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo, + userId); + } + } + pi.receivers = ArrayUtils.trimToSize(res, num); + } + } + } + if ((flags & PackageManager.GET_SERVICES) != 0) { + if (pkg.getServices() != null) { + final int size = pkg.getServices().size(); + if (size > 0) { + int num = 0; + final ServiceInfo[] res = new ServiceInfo[size]; + for (int i = 0; i < size; i++) { + final ComponentParseUtils.ParsedService s = pkg.getServices().get(i); + if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), s, flags)) { + res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo, + userId); + } + } + pi.services = ArrayUtils.trimToSize(res, num); + } + } + } + if ((flags & PackageManager.GET_PROVIDERS) != 0) { + if (pkg.getProviders() != null) { + final int size = pkg.getProviders().size(); + if (size > 0) { + int num = 0; + final ProviderInfo[] res = new ProviderInfo[size]; + for (int i = 0; i < size; i++) { + final ComponentParseUtils.ParsedProvider pr = pkg.getProviders() + .get(i); + if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), pr, flags)) { + res[num++] = generateProviderInfo(pkg, pr, flags, state, + applicationInfo, userId); + } + } + pi.providers = ArrayUtils.trimToSize(res, num); + } + } + } + if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) { + if (pkg.getInstrumentations() != null) { + int N = pkg.getInstrumentations().size(); + if (N > 0) { + pi.instrumentation = new InstrumentationInfo[N]; + for (int i = 0; i < N; i++) { + pi.instrumentation[i] = generateInstrumentationInfo( + pkg.getInstrumentations().get(i), pkg, flags); + } + } + } + } + if ((flags & PackageManager.GET_PERMISSIONS) != 0) { + if (pkg.getPermissions() != null) { + int N = ArrayUtils.size(pkg.getPermissions()); + if (N > 0) { + pi.permissions = new PermissionInfo[N]; + for (int i = 0; i < N; i++) { + pi.permissions[i] = generatePermissionInfo( + pkg.getPermissions().get(i), + flags + ); + } + } + } + if (pkg.getRequestedPermissions() != null) { + int N = pkg.getRequestedPermissions().size(); + if (N > 0) { + pi.requestedPermissions = new String[N]; + pi.requestedPermissionsFlags = new int[N]; + for (int i = 0; i < N; i++) { + final String perm = pkg.getRequestedPermissions().get(i); + pi.requestedPermissions[i] = perm; + // The notion of required permissions is deprecated but for compatibility. + pi.requestedPermissionsFlags[i] |= + PackageInfo.REQUESTED_PERMISSION_REQUIRED; + if (grantedPermissions != null && grantedPermissions.contains(perm)) { + pi.requestedPermissionsFlags[i] |= + PackageInfo.REQUESTED_PERMISSION_GRANTED; + } + } + } + } + } + + PackageParser.SigningDetails signingDetails = pkg.getSigningDetails(); + // deprecated method of getting signing certificates + if ((flags & PackageManager.GET_SIGNATURES) != 0) { + if (signingDetails.hasPastSigningCertificates()) { + // Package has included signing certificate rotation information. Return the oldest + // cert so that programmatic checks keep working even if unaware of key rotation. + pi.signatures = new Signature[1]; + pi.signatures[0] = signingDetails.pastSigningCertificates[0]; + } else if (signingDetails.hasSignatures()) { + // otherwise keep old behavior + int numberOfSigs = signingDetails.signatures.length; + pi.signatures = new Signature[numberOfSigs]; + System.arraycopy(signingDetails.signatures, 0, pi.signatures, 0, + numberOfSigs); + } + } + + // replacement for GET_SIGNATURES + if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) { + if (signingDetails != PackageParser.SigningDetails.UNKNOWN) { + // only return a valid SigningInfo if there is signing information to report + pi.signingInfo = new SigningInfo(signingDetails); + } else { + pi.signingInfo = null; + } + } + + return pi; + } + + @Nullable + public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg, + @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) { + + if (pkg == null) return null; + if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) { + return null; + } + + // Make shallow copy so we can store the metadata/libraries safely + ApplicationInfo ai = pkg.toAppInfoWithoutState(); + ai.initForUser(userId); + if ((flags & PackageManager.GET_META_DATA) == 0) { + ai.metaData = null; + } + if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) { + ai.sharedLibraryFiles = null; + ai.sharedLibraryInfos = null; + } + if (state.stopped) { + ai.flags |= ApplicationInfo.FLAG_STOPPED; + } else { + ai.flags &= ~ApplicationInfo.FLAG_STOPPED; + } + updateApplicationInfo(ai, flags, state); + + return ai; + } + + private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, + @Nullable ApplicationInfo applicationInfo, int userId) { + if (a == null) return null; + if (!checkUseInstalledOrHidden(pkg, state, flags)) { + return null; + } + if (applicationInfo == null) { + applicationInfo = generateApplicationInfo(pkg, flags, state, userId); + } + // Make shallow copies so we can store the metadata safely + ActivityInfo ai = new ActivityInfo(); + assignSharedFieldsForComponentInfo(ai, a); + ai.targetActivity = a.targetActivity; + ai.processName = a.getProcessName(); + ai.exported = a.exported; + ai.theme = a.theme; + ai.uiOptions = a.uiOptions; + ai.parentActivityName = a.parentActivityName; + ai.permission = a.getPermission(); + ai.taskAffinity = a.taskAffinity; + ai.flags = a.flags; + ai.privateFlags = a.privateFlags; + ai.launchMode = a.launchMode; + ai.documentLaunchMode = a.documentLaunchMode; + ai.maxRecents = a.maxRecents; + ai.configChanges = a.configChanges; + ai.softInputMode = a.softInputMode; + ai.persistableMode = a.persistableMode; + ai.lockTaskLaunchMode = a.lockTaskLaunchMode; + ai.screenOrientation = a.screenOrientation; + ai.resizeMode = a.resizeMode; + ai.maxAspectRatio = a.maxAspectRatio; + ai.minAspectRatio = a.minAspectRatio; + ai.requestedVrComponent = a.requestedVrComponent; + ai.rotationAnimation = a.rotationAnimation; + ai.colorMode = a.colorMode; + ai.windowLayout = a.windowLayout; + ai.metaData = a.metaData; + ai.applicationInfo = applicationInfo; + return ai; + } + + public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) { + return generateActivityInfo(pkg, a, flags, state, null, userId); + } + + private static ServiceInfo generateServiceInfo(AndroidPackage pkg, + ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags, + PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) { + if (s == null) return null; + if (!checkUseInstalledOrHidden(pkg, state, flags)) { + return null; + } + if (applicationInfo == null) { + applicationInfo = generateApplicationInfo(pkg, flags, state, userId); + } + // Make shallow copies so we can store the metadata safely + ServiceInfo si = new ServiceInfo(); + assignSharedFieldsForComponentInfo(si, s); + si.exported = s.exported; + si.flags = s.flags; + si.metaData = s.metaData; + si.permission = s.getPermission(); + si.processName = s.getProcessName(); + si.mForegroundServiceType = s.foregroundServiceType; + si.metaData = s.metaData; + si.applicationInfo = applicationInfo; + return si; + } + + public static ServiceInfo generateServiceInfo(AndroidPackage pkg, + ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags, + PackageUserState state, int userId) { + return generateServiceInfo(pkg, s, flags, state, null, userId); + } + + private static ProviderInfo generateProviderInfo(AndroidPackage pkg, + ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags, + PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) { + if (p == null) return null; + if (!checkUseInstalledOrHidden(pkg, state, flags)) { + return null; + } + if (applicationInfo == null) { + applicationInfo = generateApplicationInfo(pkg, flags, state, userId); + } + // Make shallow copies so we can store the metadata safely + ProviderInfo pi = new ProviderInfo(); + assignSharedFieldsForComponentInfo(pi, p); + pi.exported = p.exported; + pi.flags = p.flags; + pi.processName = p.getProcessName(); + pi.authority = p.getAuthority(); + pi.isSyncable = p.isSyncable; + pi.readPermission = p.getReadPermission(); + pi.writePermission = p.getWritePermission(); + pi.grantUriPermissions = p.grantUriPermissions; + pi.forceUriPermissions = p.forceUriPermissions; + pi.multiprocess = p.multiProcess; + pi.initOrder = p.initOrder; + pi.uriPermissionPatterns = p.uriPermissionPatterns; + pi.pathPermissions = p.pathPermissions; + pi.metaData = p.metaData; + if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { + pi.uriPermissionPatterns = null; + } + pi.applicationInfo = applicationInfo; + return pi; + } + + public static ProviderInfo generateProviderInfo(AndroidPackage pkg, + ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags, + PackageUserState state, int userId) { + return generateProviderInfo(pkg, p, flags, state, null, userId); + } + + public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i, + AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags) { + if (i == null) return null; + + InstrumentationInfo ii = new InstrumentationInfo(); + assignSharedFieldsForPackageItemInfo(ii, i); + ii.targetPackage = i.getTargetPackage(); + ii.targetProcesses = i.getTargetProcesses(); + ii.handleProfiling = i.handleProfiling; + ii.functionalTest = i.functionalTest; + + ii.sourceDir = pkg.getBaseCodePath(); + ii.publicSourceDir = pkg.getBaseCodePath(); + ii.splitNames = pkg.getSplitNames(); + ii.splitSourceDirs = pkg.getSplitCodePaths(); + ii.splitPublicSourceDirs = pkg.getSplitCodePaths(); + ii.splitDependencies = pkg.getSplitDependencies(); + ii.dataDir = pkg.getDataDir(); + ii.deviceProtectedDataDir = pkg.getDeviceProtectedDataDir(); + ii.credentialProtectedDataDir = pkg.getCredentialProtectedDataDir(); + ii.primaryCpuAbi = pkg.getPrimaryCpuAbi(); + ii.secondaryCpuAbi = pkg.getSecondaryCpuAbi(); + ii.nativeLibraryDir = pkg.getNativeLibraryDir(); + ii.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir(); + + if ((flags & PackageManager.GET_META_DATA) == 0) { + return ii; + } + ii.metaData = i.metaData; + return ii; + } + + public static PermissionInfo generatePermissionInfo(ParsedPermission p, + @PackageManager.ComponentInfoFlags int flags) { + if (p == null) return null; + + PermissionInfo pi = new PermissionInfo(p.backgroundPermission); + assignSharedFieldsForPackageItemInfo(pi, p); + pi.group = p.getGroup(); + pi.requestRes = p.requestRes; + pi.protectionLevel = p.protectionLevel; + pi.descriptionRes = p.descriptionRes; + pi.flags = p.flags; + + if ((flags & PackageManager.GET_META_DATA) == 0) { + return pi; + } + pi.metaData = p.metaData; + return pi; + } + + public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg, + @PackageManager.ComponentInfoFlags int flags) { + if (pg == null) return null; + + PermissionGroupInfo pgi = new PermissionGroupInfo( + pg.requestDetailResourceId, + pg.backgroundRequestResourceId, + pg.backgroundRequestDetailResourceId + ); + assignSharedFieldsForPackageItemInfo(pgi, pg); + pgi.priority = pg.priority; + pgi.requestRes = pg.requestRes; + pgi.flags = pg.flags; + + if ((flags & PackageManager.GET_META_DATA) == 0) { + return pgi; + } + pgi.metaData = pg.metaData; + return pgi; + } + + private static void updateApplicationInfo(ApplicationInfo ai, + @PackageManager.ApplicationInfoFlags int flags, + PackageUserState state) { + // CompatibilityMode is global state. + if (!PackageParser.sCompatibilityModeEnabled) { + ai.disableCompatibilityMode(); + } + if (state.installed) { + ai.flags |= ApplicationInfo.FLAG_INSTALLED; + } else { + ai.flags &= ~ApplicationInfo.FLAG_INSTALLED; + } + if (state.suspended) { + ai.flags |= ApplicationInfo.FLAG_SUSPENDED; + } else { + ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED; + } + if (state.instantApp) { + ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT; + } else { + ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT; + } + if (state.virtualPreload) { + ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD; + } else { + ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD; + } + if (state.hidden) { + ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN; + } else { + ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN; + } + if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + ai.enabled = true; + } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { + ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0; + } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED + || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { + ai.enabled = false; + } + ai.enabledSetting = state.enabled; + if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { + ai.category = state.categoryHint; + } + if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { + ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName); + } + ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state); + ai.resourceDirs = state.overlayPaths; + ai.icon = (PackageParser.sUseRoundIcon && ai.roundIconRes != 0) + ? ai.roundIconRes : ai.iconRes; + } + + private static void assignSharedFieldsForPackageItemInfo(PackageItemInfo packageItemInfo, + ComponentParseUtils.ParsedComponent parsedComponent) { + packageItemInfo.banner = parsedComponent.banner; + packageItemInfo.icon = parsedComponent.icon; + packageItemInfo.labelRes = parsedComponent.labelRes; + packageItemInfo.logo = parsedComponent.logo; + packageItemInfo.name = parsedComponent.className; + packageItemInfo.nonLocalizedLabel = parsedComponent.nonLocalizedLabel; + packageItemInfo.packageName = parsedComponent.getPackageName(); + } + + private static void assignSharedFieldsForComponentInfo(ComponentInfo componentInfo, + ComponentParseUtils.ParsedComponent parsedComponent) { + assignSharedFieldsForPackageItemInfo(componentInfo, parsedComponent); + componentInfo.descriptionRes = parsedComponent.descriptionRes; + componentInfo.directBootAware = parsedComponent.directBootAware; + componentInfo.enabled = parsedComponent.enabled; + componentInfo.splitName = parsedComponent.getSplitName(); + } + +} diff --git a/core/java/android/content/pm/parsing/ParsedPackage.java b/core/java/android/content/pm/parsing/ParsedPackage.java new file mode 100644 index 000000000000..05cf586522f2 --- /dev/null +++ b/core/java/android/content/pm/parsing/ParsedPackage.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing; + +import android.content.pm.PackageParser; + +/** + * Methods used for mutation after direct package parsing, mostly done inside + * {@link com.android.server.pm.PackageManagerService}. + * + * Java disallows defining this as an inner interface, so this must be a separate file. + * + * @hide + */ +public interface ParsedPackage extends AndroidPackage { + + AndroidPackage hideAsFinal(); + + ParsedPackage addUsesLibrary(int index, String libraryName); + + ParsedPackage addUsesOptionalLibrary(int index, String libraryName); + + ParsedPackage capPermissionPriorities(); + + ParsedPackage clearAdoptPermissions(); + + ParsedPackage clearOriginalPackages(); + + ParsedPackage clearProtectedBroadcasts(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #setCodePath(String)} + */ + @Deprecated + ParsedPackage setApplicationInfoCodePath(String applicationInfoCodePath); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #setCodePath(String)} + */ + @Deprecated + ParsedPackage setApplicationInfoResourcePath(String applicationInfoResourcePath); + + ParsedPackage setBaseCodePath(String baseCodePath); + + ParsedPackage setCodePath(String codePath); + + ParsedPackage setCpuAbiOverride(String cpuAbiOverride); + + ParsedPackage setNativeLibraryDir(String nativeLibraryDir); + + ParsedPackage setNativeLibraryRootDir(String nativeLibraryRootDir); + + ParsedPackage setPackageName(String packageName); + + ParsedPackage setPrimaryCpuAbi(String primaryCpuAbi); + + ParsedPackage setProcessName(String processName); + + ParsedPackage setRealPackage(String realPackage); + + ParsedPackage setSecondaryCpuAbi(String secondaryCpuAbi); + + ParsedPackage setSigningDetails(PackageParser.SigningDetails signingDetails); + + ParsedPackage setSplitCodePaths(String[] splitCodePaths); + + ParsedPackage initForUser(int userId); + + ParsedPackage setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa); + + ParsedPackage setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware); + + ParsedPackage setFactoryTest(boolean factoryTest); + + ParsedPackage markNotActivitiesAsNotExportedIfSingleUser(); + + ParsedPackage setOdm(boolean odm); + + ParsedPackage setOem(boolean oem); + + ParsedPackage setPrivileged(boolean privileged); + + ParsedPackage setProduct(boolean product); + + ParsedPackage setSignedWithPlatformKey(boolean signedWithPlatformKey); + + ParsedPackage setSystem(boolean system); + + ParsedPackage setSystemExt(boolean systemExt); + + ParsedPackage setUpdatedSystemApp(boolean updatedSystemApp); + + ParsedPackage setVendor(boolean vendor); + + ParsedPackage removePermission(int index); + + ParsedPackage removeUsesLibrary(String libraryName); + + ParsedPackage removeUsesOptionalLibrary(String libraryName); + + ParsedPackage setApplicationInfoBaseResourcePath(String applicationInfoBaseResourcePath); + + ParsedPackage setApplicationInfoSplitResourcePaths( + String[] applicationInfoSplitResourcePaths); + + ParsedPackage setApplicationVolumeUuid(String applicationVolumeUuid); + + ParsedPackage setCoreApp(boolean coreApp); + + ParsedPackage setIsStub(boolean isStub); + + // TODO(b/135203078): Remove entirely + ParsedPackage setPackageSettingCallback(PackageSettingCallback packageSettingCallback); + + ParsedPackage setRestrictUpdateHash(byte[] restrictUpdateHash); + + ParsedPackage setSeInfo(String seInfo); + + ParsedPackage setSeInfoUser(String seInfoUser); + + ParsedPackage setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir); + + ParsedPackage setUid(int uid); + + ParsedPackage setVersionCode(int versionCode); + + ParsedPackage setVersionCodeMajor(int versionCodeMajor); + + // TODO(b/135203078): Move logic earlier in parse chain so nothing needs to be reverted + ParsedPackage setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage); + + ParsedPackage setDirectBootAware(boolean directBootAware); + + ParsedPackage setPersistent(boolean persistent); + + interface PackageSettingCallback { + default void setAndroidPackage(AndroidPackage pkg){} + } +} diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java new file mode 100644 index 000000000000..aff1b2e05eaf --- /dev/null +++ b/core/java/android/content/pm/parsing/ParsingPackage.java @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing; + +import android.annotation.Nullable; +import android.content.Intent; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageParser; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.os.Bundle; +import android.util.ArraySet; +import android.util.SparseArray; + +import java.security.PublicKey; + +/** + * Methods used for mutation during direct package parsing. + * + * Java disallows defining this as an inner interface, so this must be a separate file. + * + * @hide + */ +public interface ParsingPackage extends AndroidPackage { + + ParsingPackage addActivity(ParsedActivity parsedActivity); + + ParsingPackage addAdoptPermission(String adoptPermission); + + ParsingPackage addConfigPreference(ConfigurationInfo configPreference); + + ParsingPackage addFeatureGroup(FeatureGroupInfo featureGroup); + + ParsingPackage addImplicitPermission(String permission); + + ParsingPackage addInstrumentation(ParsedInstrumentation instrumentation); + + ParsingPackage addKeySet(String keySetName, PublicKey publicKey); + + ParsingPackage addLibraryName(String libraryName); + + ParsingPackage addOriginalPackage(String originalPackage); + + ParsingPackage addOverlayable(String overlayableName, String actorName); + + ParsingPackage addPermission(ParsedPermission permission); + + ParsingPackage addPermissionGroup(ParsedPermissionGroup permissionGroup); + + ParsingPackage addPreferredActivityFilter(ParsedActivityIntentInfo activityIntentInfo); + + ParsingPackage addProtectedBroadcast(String protectedBroadcast); + + ParsingPackage addProvider(ParsedProvider parsedProvider); + + ParsingPackage addReceiver(ParsedActivity parsedReceiver); + + ParsingPackage addReqFeature(FeatureInfo reqFeature); + + ParsingPackage addRequestedPermission(String permission); + + ParsingPackage addService(ParsedService parsedService); + + ParsingPackage addUsesLibrary(String libraryName); + + ParsingPackage addUsesOptionalLibrary(String libraryName); + + ParsingPackage addUsesStaticLibrary(String libraryName); + + ParsingPackage addUsesStaticLibraryCertDigests(String[] certSha256Digests); + + ParsingPackage addUsesStaticLibraryVersion(long version); + + ParsingPackage addQueriesIntent(Intent intent); + + ParsingPackage addQueriesPackage(String packageName); + + ParsingPackage asSplit( + String[] splitNames, + String[] splitCodePaths, + int[] splitRevisionCodes, + @Nullable SparseArray<int[]> splitDependencies + ); + + ParsingPackage setAppMetaData(Bundle appMetaData); + + ParsingPackage setForceQueryable(boolean forceQueryable); + + ParsingPackage setMaxAspectRatio(float maxAspectRatio); + + ParsingPackage setMinAspectRatio(float minAspectRatio); + + ParsingPackage setName(String name); + + ParsingPackage setPermission(String permission); + + ParsingPackage setProcessName(String processName); + + ParsingPackage setSharedUserId(String sharedUserId); + + ParsingPackage setStaticSharedLibName(String staticSharedLibName); + + ParsingPackage setTaskAffinity(String taskAffinity); + + ParsingPackage setTargetSdkVersion(int targetSdkVersion); + + ParsingPackage setUiOptions(int uiOptions); + + ParsingPackage setBaseHardwareAccelerated(boolean baseHardwareAccelerated); + + ParsingPackage setActivitiesResizeModeResizeable(boolean resizeable); + + ParsingPackage setActivitiesResizeModeResizeableViaSdkVersion(boolean resizeableViaSdkVersion); + + ParsingPackage setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture); + + ParsingPackage setAllowBackup(boolean allowBackup); + + ParsingPackage setAllowClearUserData(boolean allowClearUserData); + + ParsingPackage setAllowClearUserDataOnFailedRestore(boolean allowClearUserDataOnFailedRestore); + + ParsingPackage setAllowTaskReparenting(boolean allowTaskReparenting); + + ParsingPackage setIsOverlay(boolean isOverlay); + + ParsingPackage setBackupInForeground(boolean backupInForeground); + + ParsingPackage setCantSaveState(boolean cantSaveState); + + ParsingPackage setDebuggable(boolean debuggable); + + ParsingPackage setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage); + + ParsingPackage setDirectBootAware(boolean directBootAware); + + ParsingPackage setExternalStorage(boolean externalStorage); + + ParsingPackage setExtractNativeLibs(boolean extractNativeLibs); + + ParsingPackage setFullBackupOnly(boolean fullBackupOnly); + + ParsingPackage setHasCode(boolean hasCode); + + ParsingPackage setHasFragileUserData(boolean hasFragileUserData); + + ParsingPackage setIsGame(boolean isGame); + + ParsingPackage setIsolatedSplitLoading(boolean isolatedSplitLoading); + + ParsingPackage setKillAfterRestore(boolean killAfterRestore); + + ParsingPackage setLargeHeap(boolean largeHeap); + + ParsingPackage setMultiArch(boolean multiArch); + + ParsingPackage setPartiallyDirectBootAware(boolean partiallyDirectBootAware); + + ParsingPackage setPersistent(boolean persistent); + + ParsingPackage setProfileableByShell(boolean profileableByShell); + + ParsingPackage setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage); + + ParsingPackage setRestoreAnyVersion(boolean restoreAnyVersion); + + ParsingPackage setSplitHasCode(int splitIndex, boolean splitHasCode); + + ParsingPackage setStaticSharedLibrary(boolean staticSharedLibrary); + + ParsingPackage setSupportsRtl(boolean supportsRtl); + + ParsingPackage setTestOnly(boolean testOnly); + + ParsingPackage setUseEmbeddedDex(boolean useEmbeddedDex); + + ParsingPackage setUsesCleartextTraffic(boolean usesCleartextTraffic); + + ParsingPackage setUsesNonSdkApi(boolean usesNonSdkApi); + + ParsingPackage setVisibleToInstantApps(boolean visibleToInstantApps); + + ParsingPackage setVmSafeMode(boolean vmSafeMode); + + ParsingPackage removeUsesOptionalLibrary(String libraryName); + + ParsingPackage setAnyDensity(int anyDensity); + + ParsingPackage setAppComponentFactory(String appComponentFactory); + + ParsingPackage setApplicationVolumeUuid(String applicationVolumeUuid); + + ParsingPackage setBackupAgentName(String backupAgentName); + + ParsingPackage setBanner(int banner); + + ParsingPackage setCategory(int category); + + ParsingPackage setClassLoaderName(String classLoaderName); + + ParsingPackage setClassName(String className); + + ParsingPackage setCodePath(String codePath); + + ParsingPackage setCompatibleWidthLimitDp(int compatibleWidthLimitDp); + + ParsingPackage setDescriptionRes(int descriptionRes); + + ParsingPackage setEnabled(boolean enabled); + + ParsingPackage setFullBackupContent(int fullBackupContent); + + ParsingPackage setHasDomainUrls(boolean hasDomainUrls); + + ParsingPackage setIcon(int icon); + + ParsingPackage setIconRes(int iconRes); + + ParsingPackage setInstallLocation(int installLocation); + + ParsingPackage setLabelRes(int labelRes); + + ParsingPackage setLargestWidthLimitDp(int largestWidthLimitDp); + + ParsingPackage setLogo(int logo); + + ParsingPackage setManageSpaceActivityName(String manageSpaceActivityName); + + ParsingPackage setMinSdkVersion(int minSdkVersion); + + ParsingPackage setNetworkSecurityConfigRes(int networkSecurityConfigRes); + + ParsingPackage setNonLocalizedLabel(CharSequence nonLocalizedLabel); + + ParsingPackage setOverlayCategory(String overlayCategory); + + ParsingPackage setOverlayIsStatic(boolean overlayIsStatic); + + ParsingPackage setOverlayPriority(int overlayPriority); + + ParsingPackage setOverlayTarget(String overlayTarget); + + ParsingPackage setOverlayTargetName(String overlayTargetName); + + ParsingPackage setRealPackage(String realPackage); + + ParsingPackage setRequiredAccountType(String requiredAccountType); + + ParsingPackage setRequiredForAllUsers(boolean requiredForAllUsers); + + ParsingPackage setRequiresSmallestWidthDp(int requiresSmallestWidthDp); + + ParsingPackage setResizeable(int resizeable); + + ParsingPackage setRestrictUpdateHash(byte[] restrictUpdateHash); + + ParsingPackage setRestrictedAccountType(String restrictedAccountType); + + ParsingPackage setRoundIconRes(int roundIconRes); + + ParsingPackage setSharedUserLabel(int sharedUserLabel); + + ParsingPackage setSigningDetails(PackageParser.SigningDetails signingDetails); + + ParsingPackage setSplitClassLoaderName(int splitIndex, String classLoaderName); + + ParsingPackage setStaticSharedLibVersion(long staticSharedLibVersion); + + ParsingPackage setSupportsLargeScreens(int supportsLargeScreens); + + ParsingPackage setSupportsNormalScreens(int supportsNormalScreens); + + ParsingPackage setSupportsSmallScreens(int supportsSmallScreens); + + ParsingPackage setSupportsXLargeScreens(int supportsXLargeScreens); + + ParsingPackage setTargetSandboxVersion(int targetSandboxVersion); + + ParsingPackage setTheme(int theme); + + ParsingPackage setUpgradeKeySets(ArraySet<String> upgradeKeySets); + + ParsingPackage setUse32BitAbi(boolean use32BitAbi); + + ParsingPackage setVolumeUuid(String volumeUuid); + + ParsingPackage setZygotePreloadName(String zygotePreloadName); + + ParsingPackage sortActivities(); + + ParsingPackage sortReceivers(); + + ParsingPackage sortServices(); + + ParsedPackage hideAsParsed(); + + ParsingPackage setBaseRevisionCode(int baseRevisionCode); + + ParsingPackage setPreferredOrder(int preferredOrder); + + ParsingPackage setVersionName(String versionName); + + ParsingPackage setCompileSdkVersion(int compileSdkVersion); + + ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename); + + boolean usesCompatibilityMode(); +} diff --git a/core/java/android/content/pm/AndroidHidlUpdater.java b/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java index d0657e5eb8ec..81b4bc574197 100644 --- a/core/java/android/content/pm/AndroidHidlUpdater.java +++ b/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; -import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE; -import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER; -import android.content.pm.PackageParser.Package; +import android.content.pm.parsing.ParsedPackage; import android.os.Build; import com.android.internal.annotations.VisibleForTesting; @@ -33,20 +33,18 @@ import com.android.internal.annotations.VisibleForTesting; public class AndroidHidlUpdater extends PackageSharedLibraryUpdater { @Override - public void updatePackage(Package pkg) { - ApplicationInfo info = pkg.applicationInfo; - + public void updatePackage(ParsedPackage parsedPackage) { // This was the default <= P and is maintained for backwards compatibility. - boolean isLegacy = info.targetSdkVersion <= Build.VERSION_CODES.P; + boolean isLegacy = parsedPackage.getTargetSdkVersion() <= Build.VERSION_CODES.P; // Only system apps use these libraries - boolean isSystem = info.isSystemApp() || info.isUpdatedSystemApp(); + boolean isSystem = parsedPackage.isSystemApp() || parsedPackage.isUpdatedSystemApp(); if (isLegacy && isSystem) { - prefixRequiredLibrary(pkg, ANDROID_HIDL_BASE); - prefixRequiredLibrary(pkg, ANDROID_HIDL_MANAGER); + prefixRequiredLibrary(parsedPackage, ANDROID_HIDL_BASE); + prefixRequiredLibrary(parsedPackage, ANDROID_HIDL_MANAGER); } else { - removeLibrary(pkg, ANDROID_HIDL_BASE); - removeLibrary(pkg, ANDROID_HIDL_MANAGER); + removeLibrary(parsedPackage, ANDROID_HIDL_BASE); + removeLibrary(parsedPackage, ANDROID_HIDL_MANAGER); } } } diff --git a/core/java/android/content/pm/AndroidTestBaseUpdater.java b/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java index 18d3ba33552e..5fbe5b9c7250 100644 --- a/core/java/android/content/pm/AndroidTestBaseUpdater.java +++ b/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.content.Context; -import android.content.pm.PackageParser.Package; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsedPackage; import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; @@ -54,25 +55,25 @@ public class AndroidTestBaseUpdater extends PackageSharedLibraryUpdater { @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) private static final long REMOVE_ANDROID_TEST_BASE = 133396946L; - private static boolean isChangeEnabled(Package pkg) { + private static boolean isChangeEnabled(AndroidPackage pkg) { // Do not ask platform compat for system apps to prevent a boot time regression in tests. // b/142558883. - if (!pkg.applicationInfo.isSystemApp()) { + if (!pkg.isSystem()) { IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); try { return platformCompat.isChangeEnabled(REMOVE_ANDROID_TEST_BASE, - pkg.applicationInfo); + pkg.toAppInfoWithoutState()); } catch (RemoteException | NullPointerException e) { Log.e(TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e); } } // Fall back to previous behaviour. - return pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.Q; + return pkg.getTargetSdkVersion() > Build.VERSION_CODES.Q; } @Override - public void updatePackage(Package pkg) { + public void updatePackage(ParsedPackage pkg) { // Packages targeted at <= Q expect the classes in the android.test.base library // to be accessible so this maintains backward compatibility by adding the // android.test.base library to those packages. diff --git a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java b/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java index 707443b19679..613a06b636e9 100644 --- a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java +++ b/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; -import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; -import android.content.pm.PackageParser.Package; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsedPackage; import android.os.Build; import com.android.internal.annotations.VisibleForTesting; @@ -31,18 +32,17 @@ import com.android.internal.annotations.VisibleForTesting; @VisibleForTesting public class OrgApacheHttpLegacyUpdater extends PackageSharedLibraryUpdater { - private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(Package pkg) { - int targetSdkVersion = pkg.applicationInfo.targetSdkVersion; - return targetSdkVersion < Build.VERSION_CODES.P; + private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(AndroidPackage pkg) { + return pkg.getTargetSdkVersion() < Build.VERSION_CODES.P; } @Override - public void updatePackage(Package pkg) { + public void updatePackage(ParsedPackage parsedPackage) { // Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library // to be accessible so this maintains backward compatibility by adding the // org.apache.http.legacy library to those packages. - if (apkTargetsApiLevelLessThanOrEqualToOMR1(pkg)) { - prefixRequiredLibrary(pkg, ORG_APACHE_HTTP_LEGACY); + if (apkTargetsApiLevelLessThanOrEqualToOMR1(parsedPackage)) { + prefixRequiredLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY); } } } diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java index 4331bd4ac4d4..1220fc497b04 100644 --- a/core/java/android/content/pm/PackageBackwardCompatibility.java +++ b/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,14 +14,14 @@ * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER; -import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; +import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; -import android.content.pm.PackageParser.Package; +import android.content.pm.parsing.ParsedPackage; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -31,7 +31,7 @@ import java.util.List; import java.util.function.Supplier; /** - * Modifies {@link Package} in order to maintain backwards compatibility. + * Modifies {@link ParsedPackage} in order to maintain backwards compatibility. * * @hide */ @@ -60,7 +60,7 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { // will remove any references to org.apache.http.library from the package so that it does // not try and load the library when it is on the bootclasspath. boolean bootClassPathContainsATB = !addOptionalUpdater(packageUpdaters, - "android.content.pm.AndroidTestBaseUpdater", + "android.content.pm.parsing.library.AndroidTestBaseUpdater", RemoveUnnecessaryAndroidTestBaseLibrary::new); PackageSharedLibraryUpdater[] updaterArray = packageUpdaters @@ -123,20 +123,20 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { } /** - * Modify the shared libraries in the supplied {@link Package} to maintain backwards + * Modify the shared libraries in the supplied {@link ParsedPackage} to maintain backwards * compatibility. * - * @param pkg the {@link Package} to modify. + * @param parsedPackage the {@link ParsedPackage} to modify. */ @VisibleForTesting - public static void modifySharedLibraries(Package pkg) { - INSTANCE.updatePackage(pkg); + public static void modifySharedLibraries(ParsedPackage parsedPackage) { + INSTANCE.updatePackage(parsedPackage); } @Override - public void updatePackage(Package pkg) { + public void updatePackage(ParsedPackage parsedPackage) { for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) { - packageUpdater.updatePackage(pkg); + packageUpdater.updatePackage(parsedPackage); } } @@ -161,10 +161,10 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { public static class AndroidTestRunnerSplitUpdater extends PackageSharedLibraryUpdater { @Override - public void updatePackage(Package pkg) { + public void updatePackage(ParsedPackage parsedPackage) { // android.test.runner has a dependency on android.test.mock so if android.test.runner // is present but android.test.mock is not then add android.test.mock. - prefixImplicitDependency(pkg, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK); + prefixImplicitDependency(parsedPackage, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK); } } @@ -177,8 +177,8 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { extends PackageSharedLibraryUpdater { @Override - public void updatePackage(Package pkg) { - removeLibrary(pkg, ORG_APACHE_HTTP_LEGACY); + public void updatePackage(ParsedPackage parsedPackage) { + removeLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY); } } @@ -192,8 +192,8 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { extends PackageSharedLibraryUpdater { @Override - public void updatePackage(Package pkg) { - removeLibrary(pkg, ANDROID_TEST_BASE); + public void updatePackage(ParsedPackage parsedPackage) { + removeLibrary(parsedPackage, ANDROID_TEST_BASE); } } } diff --git a/core/java/android/content/pm/PackageSharedLibraryUpdater.java b/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java index 1565d9ce77d4..8b27d140a8f4 100644 --- a/core/java/android/content/pm/PackageSharedLibraryUpdater.java +++ b/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,18 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.pm.parsing.ParsedPackage; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import java.util.ArrayList; +import java.util.List; /** - * Base for classes that update a {@link PackageParser.Package}'s shared libraries. + * Base for classes that update a {@link ParsedPackage}'s shared libraries. * * @hide */ @@ -34,14 +36,13 @@ public abstract class PackageSharedLibraryUpdater { /** * Update the package's shared libraries. * - * @param pkg the package to update. + * @param parsedPackage the package to update. */ - public abstract void updatePackage(PackageParser.Package pkg); + public abstract void updatePackage(ParsedPackage parsedPackage); - static void removeLibrary(PackageParser.Package pkg, String libraryName) { - pkg.usesLibraries = ArrayUtils.remove(pkg.usesLibraries, libraryName); - pkg.usesOptionalLibraries = - ArrayUtils.remove(pkg.usesOptionalLibraries, libraryName); + static void removeLibrary(ParsedPackage parsedPackage, String libraryName) { + parsedPackage.removeUsesLibrary(libraryName) + .removeUsesOptionalLibrary(libraryName); } static @NonNull @@ -53,8 +54,8 @@ public abstract class PackageSharedLibraryUpdater { return cur; } - private static boolean isLibraryPresent(ArrayList<String> usesLibraries, - ArrayList<String> usesOptionalLibraries, String apacheHttpLegacy) { + private static boolean isLibraryPresent(List<String> usesLibraries, + List<String> usesOptionalLibraries, String apacheHttpLegacy) { return ArrayUtils.contains(usesLibraries, apacheHttpLegacy) || ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy); } @@ -65,37 +66,32 @@ public abstract class PackageSharedLibraryUpdater { * <p>If the package has an existing dependency on {@code existingLibrary} then prefix it with * the {@code implicitDependency} if it is not already in the list of libraries. * - * @param pkg the {@link PackageParser.Package} to update. + * @param parsedPackage the {@link ParsedPackage} to update. * @param existingLibrary the existing library. * @param implicitDependency the implicit dependency to add */ - void prefixImplicitDependency(PackageParser.Package pkg, String existingLibrary, + void prefixImplicitDependency(ParsedPackage parsedPackage, String existingLibrary, String implicitDependency) { - ArrayList<String> usesLibraries = pkg.usesLibraries; - ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries; + List<String> usesLibraries = parsedPackage.getUsesLibraries(); + List<String> usesOptionalLibraries = parsedPackage.getUsesOptionalLibraries(); if (!isLibraryPresent(usesLibraries, usesOptionalLibraries, implicitDependency)) { if (ArrayUtils.contains(usesLibraries, existingLibrary)) { - prefix(usesLibraries, implicitDependency); + parsedPackage.addUsesLibrary(0, implicitDependency); } else if (ArrayUtils.contains(usesOptionalLibraries, existingLibrary)) { - prefix(usesOptionalLibraries, implicitDependency); + parsedPackage.addUsesOptionalLibrary(0, implicitDependency); } - - pkg.usesLibraries = usesLibraries; - pkg.usesOptionalLibraries = usesOptionalLibraries; } } - void prefixRequiredLibrary(PackageParser.Package pkg, String libraryName) { - ArrayList<String> usesLibraries = pkg.usesLibraries; - ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries; + void prefixRequiredLibrary(ParsedPackage parsedPackage, String libraryName) { + List<String> usesLibraries = parsedPackage.getUsesLibraries(); + List<String> usesOptionalLibraries = parsedPackage.getUsesOptionalLibraries(); boolean alreadyPresent = isLibraryPresent( usesLibraries, usesOptionalLibraries, libraryName); if (!alreadyPresent) { - usesLibraries = prefix(usesLibraries, libraryName); - - pkg.usesLibraries = usesLibraries; + parsedPackage.addUsesLibrary(0, libraryName); } } } diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/parsing/library/SharedLibraryNames.java index a607a9ff682b..7b691c06718e 100644 --- a/core/java/android/content/pm/SharedLibraryNames.java +++ b/core/java/android/content/pm/parsing/library/SharedLibraryNames.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; /** * A set of shared library names diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 090629fe77cb..fa5ad39789dd 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -452,6 +452,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration if ((diff & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) { list.add("CONFIG_SMALLEST_SCREEN_SIZE"); } + if ((diff & ActivityInfo.CONFIG_DENSITY) != 0) { + list.add("CONFIG_DENSITY"); + } if ((diff & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) { list.add("CONFIG_LAYOUT_DIRECTION"); } @@ -461,6 +464,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration if ((diff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) { list.add("CONFIG_ASSETS_PATHS"); } + if ((diff & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0) { + list.add("CONFIG_WINDOW_CONFIGURATION"); + } StringBuilder builder = new StringBuilder("{"); for (int i = 0, n = list.size(); i < n; i++) { builder.append(list.get(i)); diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 2698c2de4c61..c698267b956b 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -1859,6 +1859,7 @@ public class Resources { mResId = other.mResId == null ? null : other.mResId.clone(); mForce = other.mForce == null ? null : other.mForce.clone(); mCount = other.mCount; + mHashCode = other.mHashCode; } @Override diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index 84489cfb768c..e4a4a1a771b2 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -344,7 +344,7 @@ public class ResourcesImpl { try { return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString()); } catch (Exception e) { - throw new NotFoundException("File " + tempValue.string.toString() + " from drawable " + throw new NotFoundException("File " + tempValue.string.toString() + " from " + "resource ID #0x" + Integer.toHexString(id), e); } } @@ -359,7 +359,7 @@ public class ResourcesImpl { // Note: value.string might be null NotFoundException rnf = new NotFoundException("File " + (value.string == null ? "(null)" : value.string.toString()) - + " from drawable resource ID #0x" + Integer.toHexString(id)); + + " from resource ID #0x" + Integer.toHexString(id)); rnf.initCause(e); throw rnf; } diff --git a/core/java/android/ddm/DdmHandleAppName.java b/core/java/android/ddm/DdmHandleAppName.java index 956078772ca8..de7acbaf6e55 100644 --- a/core/java/android/ddm/DdmHandleAppName.java +++ b/core/java/android/ddm/DdmHandleAppName.java @@ -17,10 +17,12 @@ package android.ddm; import android.annotation.UnsupportedAppUsage; +import android.util.Log; + import org.apache.harmony.dalvik.ddmc.Chunk; import org.apache.harmony.dalvik.ddmc.ChunkHandler; import org.apache.harmony.dalvik.ddmc.DdmServer; -import android.util.Log; + import java.nio.ByteBuffer; @@ -31,7 +33,7 @@ public class DdmHandleAppName extends ChunkHandler { public static final int CHUNK_APNM = type("APNM"); - private volatile static String mAppName = ""; + private static volatile Names sNames = new Names("", ""); private static DdmHandleAppName mInstance = new DdmHandleAppName(); @@ -66,45 +68,81 @@ public class DdmHandleAppName extends ChunkHandler { /** + * Sets all names to the same name. + */ + @UnsupportedAppUsage + public static void setAppName(String name, int userId) { + setAppName(name, name, userId); + } + + /** * Set the application name. Called when we get named, which may be * before or after DDMS connects. For the latter we need to send up * an APNM message. */ @UnsupportedAppUsage - public static void setAppName(String name, int userId) { - if (name == null || name.length() == 0) - return; + public static void setAppName(String appName, String pkgName, int userId) { + if (appName == null || appName.isEmpty() || pkgName == null || pkgName.isEmpty()) return; - mAppName = name; + sNames = new Names(appName, pkgName); // if DDMS is already connected, send the app name up - sendAPNM(name, userId); + sendAPNM(appName, pkgName, userId); } @UnsupportedAppUsage - public static String getAppName() { - return mAppName; + public static Names getNames() { + return sNames; } - /* + /** * Send an APNM (APplication NaMe) chunk. */ - private static void sendAPNM(String appName, int userId) { + private static void sendAPNM(String appName, String pkgName, int userId) { if (false) Log.v("ddm", "Sending app name"); ByteBuffer out = ByteBuffer.allocate( 4 /* appName's length */ - + appName.length()*2 /* appName */ - + 4 /* userId */); + + appName.length() * 2 /* appName */ + + 4 /* userId */ + + 4 /* pkgName's length */ + + pkgName.length() * 2 /* pkgName */); out.order(ChunkHandler.CHUNK_ORDER); out.putInt(appName.length()); putString(out, appName); out.putInt(userId); + out.putInt(pkgName.length()); + putString(out, pkgName); Chunk chunk = new Chunk(CHUNK_APNM, out); DdmServer.sendChunk(chunk); } + /** + * A class that encapsulates the app and package names into a single + * instance, effectively synchronizing the two names. + */ + static final class Names { + + private final String mAppName; + + private final String mPkgName; + + private Names(String appName, String pkgName) { + mAppName = appName; + mPkgName = pkgName; + } + + public String getAppName() { + return mAppName; + } + + public String getPkgName() { + return mPkgName; + } + + } + } diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java index 87568e857d6d..60dfc8d7ee7b 100644 --- a/core/java/android/ddm/DdmHandleHello.java +++ b/core/java/android/ddm/DdmHandleHello.java @@ -126,10 +126,9 @@ public class DdmHandleHello extends ChunkHandler { String vmVersion = System.getProperty("java.vm.version", "?"); String vmIdent = vmName + " v" + vmVersion; - //String appName = android.app.ActivityThread.currentPackageName(); - //if (appName == null) - // appName = "unknown"; - String appName = DdmHandleAppName.getAppName(); + DdmHandleAppName.Names names = DdmHandleAppName.getNames(); + String appName = names.getAppName(); + String pkgName = names.getPkgName(); VMRuntime vmRuntime = VMRuntime.getRuntime(); String instructionSetDescription = @@ -142,12 +141,13 @@ public class DdmHandleHello extends ChunkHandler { + (vmRuntime.isCheckJniEnabled() ? "true" : "false"); boolean isNativeDebuggable = vmRuntime.isNativeDebuggable(); - ByteBuffer out = ByteBuffer.allocate(28 + ByteBuffer out = ByteBuffer.allocate(32 + vmIdent.length() * 2 + appName.length() * 2 + instructionSetDescription.length() * 2 + vmFlags.length() * 2 - + 1); + + 1 + + pkgName.length() * 2); out.order(ChunkHandler.CHUNK_ORDER); out.putInt(CLIENT_PROTOCOL_VERSION); out.putInt(android.os.Process.myPid()); @@ -161,6 +161,8 @@ public class DdmHandleHello extends ChunkHandler { out.putInt(vmFlags.length()); putString(out, vmFlags); out.put((byte)(isNativeDebuggable ? 1 : 0)); + out.putInt(pkgName.length()); + putString(out, pkgName); Chunk reply = new Chunk(CHUNK_HELO, out); diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java index c8bf570e1bc8..191516b5b992 100644 --- a/core/java/android/hardware/biometrics/BiometricConstants.java +++ b/core/java/android/hardware/biometrics/BiometricConstants.java @@ -86,12 +86,10 @@ public interface BiometricConstants { int BIOMETRIC_ERROR_LOCKOUT = 7; /** - * Hardware vendors may extend this list if there are conditions that do not fall under one of - * the above categories. Vendors are responsible for providing error strings for these errors. - * These messages are typically reserved for internal operations such as enrollment, but may be - * used to express vendor errors not otherwise covered. Applications are expected to show the - * error message string if they happen, but are advised not to rely on the message id since they - * will be device and vendor-specific + * OEMs should use this constant if there are conditions that do not fit under any of the other + * publicly defined constants, and must provide appropriate strings for these + * errors to the {@link BiometricPrompt.AuthenticationCallback#onAuthenticationError(int, + * CharSequence)} callback. OEMs should expect that the error message will be shown to users. */ int BIOMETRIC_ERROR_VENDOR = 8; diff --git a/core/java/android/hardware/display/DisplayViewport.java b/core/java/android/hardware/display/DisplayViewport.java index f2c50b5cc464..5adf948de348 100644 --- a/core/java/android/hardware/display/DisplayViewport.java +++ b/core/java/android/hardware/display/DisplayViewport.java @@ -134,7 +134,9 @@ public final class DisplayViewport { result += prime * result + deviceWidth; result += prime * result + deviceHeight; result += prime * result + uniqueId.hashCode(); - result += prime * result + physicalPort; + if (physicalPort != null) { + result += prime * result + physicalPort.hashCode(); + } result += prime * result + type; return result; } @@ -142,11 +144,12 @@ public final class DisplayViewport { // For debugging purposes. @Override public String toString() { + final Integer port = physicalPort == null ? null : Byte.toUnsignedInt(physicalPort); return "DisplayViewport{type=" + typeToString(type) + ", valid=" + valid + ", displayId=" + displayId + ", uniqueId='" + uniqueId + "'" - + ", physicalPort=" + physicalPort + + ", physicalPort=" + port + ", orientation=" + orientation + ", logicalFrame=" + logicalFrame + ", physicalFrame=" + physicalFrame diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java index c9a999cfdf17..1ae44e169851 100644 --- a/core/java/android/net/InterfaceConfiguration.java +++ b/core/java/android/net/InterfaceConfiguration.java @@ -20,8 +20,6 @@ import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; -import com.google.android.collect.Sets; - import java.util.HashSet; /** @@ -32,7 +30,7 @@ import java.util.HashSet; public class InterfaceConfiguration implements Parcelable { private String mHwAddr; private LinkAddress mAddr; - private HashSet<String> mFlags = Sets.newHashSet(); + private HashSet<String> mFlags = new HashSet<>(); // Must be kept in sync with constant in INetd.aidl private static final String FLAG_UP = "up"; diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 15ff69e7fd2a..a9c5a9118a31 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -909,8 +909,11 @@ public class Binder implements IBinder { } /** - * Handle a call to {@link #shellCommand}. The default implementation simply prints - * an error message. Override and replace with your own. + * Handle a call to {@link #shellCommand}. + * + * <p>The default implementation performs a caller check to make sure the caller UID is of + * SHELL or ROOT, and then call {@link #handleShellCommand}. + * * <p class="caution">Note: no permission checking is done before calling this method; you must * apply any security checks as appropriate for the command being executed. * Consider using {@link ShellCommand} to help in the implementation.</p> @@ -921,6 +924,12 @@ public class Binder implements IBinder { @NonNull String[] args, @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) throws RemoteException { + final int callingUid = Binder.getCallingUid(); + if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) { + resultReceiver.send(-1, null); + throw new SecurityException("Shell commands are only callable by ADB"); + } + // First, convert in, out and err to @NonNull, by redirecting any that's null to /dev/null. try { if (in == null) { @@ -961,19 +970,23 @@ public class Binder implements IBinder { /** * System services can implement this method to implement ADB shell commands. * - * TODO More Javadoc. - * TODO Add a generic way to define subcommands and their permissions. + * <p>A system binder service can implement it to handle shell commands on ADB. For example, + * the Job Scheduler service implements it to handle <code>adb shell cmd jobscheduler</code>. * - * @param in standard input. - * @param out standard output. - * @param err standard error. + * <p>Commands are only executable by ADB shell; i.e. only {@link Process#SHELL_UID} and + * {@link Process#ROOT_UID} can call them. + * + * @param in standard input + * @param out standard output + * @param err standard error * @param args arguments passed to the command. Can be empty. The first argument is typically * a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}. + * @return the status code returned from the <code>cmd</code> command. * * @hide */ - // @SystemApi TODO Make it a system API. - protected int handleShellCommand(@NonNull ParcelFileDescriptor in, + @SystemApi + public int handleShellCommand(@NonNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args) { FileOutputStream ferr = new FileOutputStream(err.getFileDescriptor()); diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index 1456a734394d..e132c11d6c8e 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -21,6 +21,7 @@ import android.annotation.UnsupportedAppUsage; import com.android.internal.os.Zygote; +import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; /** @@ -107,12 +108,15 @@ public final class Trace { private static final int MAX_SECTION_NAME_LEN = 127; // Must be volatile to avoid word tearing. + // This is only kept in case any apps get this by reflection but do not + // check the return value for null. @UnsupportedAppUsage private static volatile long sEnabledTags = TRACE_TAG_NOT_READY; private static int sZygoteDebugFlags = 0; @UnsupportedAppUsage + @CriticalNative private static native long nativeGetEnabledTags(); private static native void nativeSetAppTracingAllowed(boolean allowed); private static native void nativeSetTracingEnabled(boolean allowed); @@ -128,47 +132,10 @@ public final class Trace { @FastNative private static native void nativeAsyncTraceEnd(long tag, String name, int cookie); - static { - // We configure two separate change callbacks, one in Trace.cpp and one here. The - // native callback reads the tags from the system property, and this callback - // reads the value that the native code retrieved. It's essential that the native - // callback executes first. - // - // The system provides ordering through a priority level. Callbacks made through - // SystemProperties.addChangeCallback currently have a negative priority, while - // our native code is using a priority of zero. - SystemProperties.addChangeCallback(() -> { - cacheEnabledTags(); - if ((sZygoteDebugFlags & Zygote.DEBUG_JAVA_DEBUGGABLE) != 0) { - traceCounter(TRACE_TAG_ALWAYS, "java_debuggable", 1); - } - }); - } - private Trace() { } /** - * Caches a copy of the enabled-tag bits. The "master" copy is held by the native code, - * and comes from the PROPERTY_TRACE_TAG_ENABLEFLAGS property. - * <p> - * If the native code hasn't yet read the property, we will cause it to do one-time - * initialization. We don't want to do this during class init, because this class is - * preloaded, so all apps would be stuck with whatever the zygote saw. (The zygote - * doesn't see the system-property update broadcasts.) - * <p> - * We want to defer initialization until the first use by an app, post-zygote. - * <p> - * We're okay if multiple threads call here simultaneously -- the native state is - * synchronized, and sEnabledTags is volatile (prevents word tearing). - */ - private static long cacheEnabledTags() { - long tags = nativeGetEnabledTags(); - sEnabledTags = tags; - return tags; - } - - /** * Returns true if a trace tag is enabled. * * @param traceTag The trace tag to check. @@ -178,10 +145,7 @@ public final class Trace { */ @UnsupportedAppUsage public static boolean isTagEnabled(long traceTag) { - long tags = sEnabledTags; - if (tags == TRACE_TAG_NOT_READY) { - tags = cacheEnabledTags(); - } + long tags = nativeGetEnabledTags(); return (tags & traceTag) != 0; } @@ -210,10 +174,6 @@ public final class Trace { @UnsupportedAppUsage public static void setAppTracingAllowed(boolean allowed) { nativeSetAppTracingAllowed(allowed); - - // Setting whether app tracing is allowed may change the tags, so we update the cached - // tags here. - cacheEnabledTags(); } /** @@ -227,10 +187,6 @@ public final class Trace { public static void setTracingEnabled(boolean enabled, int debugFlags) { nativeSetTracingEnabled(enabled); sZygoteDebugFlags = debugFlags; - - // Setting whether tracing is enabled may change the tags, so we update the cached tags - // here. - cacheEnabledTags(); } /** diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 9e9cd9218a0f..137f53782124 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -24,6 +24,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.StringDef; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -1112,6 +1113,82 @@ public class UserManager { */ public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending"; + /** + * List of key values that can be passed into the various user restriction related methods + * in {@link UserManager} & {@link DevicePolicyManager}. + * Note: This is slightly different from the real set of user restrictions listed in {@link + * com.android.server.pm.UserRestrictionsUtils#USER_RESTRICTIONS}. For example + * {@link #KEY_RESTRICTIONS_PENDING} is not a real user restriction, but is a a legitimate + * value that can be passed into {@link #hasUserRestriction(String)}. + * @hide + */ + @StringDef(value = { + DISALLOW_MODIFY_ACCOUNTS, + DISALLOW_CONFIG_WIFI, + DISALLOW_CONFIG_LOCALE, + DISALLOW_INSTALL_APPS, + DISALLOW_UNINSTALL_APPS, + DISALLOW_SHARE_LOCATION, + DISALLOW_AIRPLANE_MODE, + DISALLOW_CONFIG_BRIGHTNESS, + DISALLOW_AMBIENT_DISPLAY, + DISALLOW_CONFIG_SCREEN_TIMEOUT, + DISALLOW_INSTALL_UNKNOWN_SOURCES, + DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, + DISALLOW_CONFIG_BLUETOOTH, + DISALLOW_BLUETOOTH, + DISALLOW_BLUETOOTH_SHARING, + DISALLOW_USB_FILE_TRANSFER, + DISALLOW_CONFIG_CREDENTIALS, + DISALLOW_REMOVE_USER, + DISALLOW_REMOVE_MANAGED_PROFILE, + DISALLOW_DEBUGGING_FEATURES, + DISALLOW_CONFIG_VPN, + DISALLOW_CONFIG_LOCATION, + DISALLOW_CONFIG_DATE_TIME, + DISALLOW_CONFIG_TETHERING, + DISALLOW_NETWORK_RESET, + DISALLOW_FACTORY_RESET, + DISALLOW_ADD_USER, + DISALLOW_ADD_MANAGED_PROFILE, + ENSURE_VERIFY_APPS, + DISALLOW_CONFIG_CELL_BROADCASTS, + DISALLOW_CONFIG_MOBILE_NETWORKS, + DISALLOW_APPS_CONTROL, + DISALLOW_MOUNT_PHYSICAL_MEDIA, + DISALLOW_UNMUTE_MICROPHONE, + DISALLOW_ADJUST_VOLUME, + DISALLOW_OUTGOING_CALLS, + DISALLOW_SMS, + DISALLOW_FUN, + DISALLOW_CREATE_WINDOWS, + DISALLOW_SYSTEM_ERROR_DIALOGS, + DISALLOW_CROSS_PROFILE_COPY_PASTE, + DISALLOW_OUTGOING_BEAM, + DISALLOW_WALLPAPER, + DISALLOW_SET_WALLPAPER, + DISALLOW_SAFE_BOOT, + DISALLOW_RECORD_AUDIO, + DISALLOW_RUN_IN_BACKGROUND, + DISALLOW_CAMERA, + DISALLOW_UNMUTE_DEVICE, + DISALLOW_DATA_ROAMING, + DISALLOW_SET_USER_ICON, + DISALLOW_OEM_UNLOCK, + DISALLOW_UNIFIED_PASSWORD, + ALLOW_PARENT_PROFILE_APP_LINKING, + DISALLOW_AUTOFILL, + DISALLOW_CONTENT_CAPTURE, + DISALLOW_CONTENT_SUGGESTIONS, + DISALLOW_USER_SWITCH, + DISALLOW_SHARE_INTO_MANAGED_PROFILE, + DISALLOW_PRINTING, + DISALLOW_CONFIG_PRIVATE_DNS, + KEY_RESTRICTIONS_PENDING, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface UserRestrictionKey {} + private static final String ACTION_CREATE_USER = "android.os.action.CREATE_USER"; /** @@ -2026,7 +2103,8 @@ public class UserManager { @SystemApi @UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) - public int getUserRestrictionSource(String restrictionKey, UserHandle userHandle) { + public int getUserRestrictionSource(@UserRestrictionKey String restrictionKey, + UserHandle userHandle) { try { return mService.getUserRestrictionSource(restrictionKey, userHandle.getIdentifier()); } catch (RemoteException re) { @@ -2045,7 +2123,7 @@ public class UserManager { @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public List<EnforcingUser> getUserRestrictionSources( - String restrictionKey, UserHandle userHandle) { + @UserRestrictionKey String restrictionKey, UserHandle userHandle) { try { return mService.getUserRestrictionSources(restrictionKey, userHandle.getIdentifier()); } catch (RemoteException re) { @@ -2091,7 +2169,8 @@ public class UserManager { * @param userHandle the UserHandle of the user for whom to retrieve the restrictions. */ @UnsupportedAppUsage - public boolean hasBaseUserRestriction(String restrictionKey, UserHandle userHandle) { + public boolean hasBaseUserRestriction(@UserRestrictionKey String restrictionKey, + UserHandle userHandle) { try { return mService.hasBaseUserRestriction(restrictionKey, userHandle.getIdentifier()); } catch (RemoteException re) { @@ -2162,7 +2241,7 @@ public class UserManager { * @param restrictionKey The string key representing the restriction. * @return {@code true} if the current user has the given restriction, {@code false} otherwise. */ - public boolean hasUserRestriction(String restrictionKey) { + public boolean hasUserRestriction(@UserRestrictionKey String restrictionKey) { return hasUserRestrictionForUser(restrictionKey, Process.myUserHandle()); } @@ -2174,7 +2253,8 @@ public class UserManager { * @param userHandle the UserHandle of the user for whom to retrieve the restrictions. */ @UnsupportedAppUsage - public boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) { + public boolean hasUserRestriction(@UserRestrictionKey String restrictionKey, + UserHandle userHandle) { return hasUserRestrictionForUser(restrictionKey, userHandle); } @@ -2194,7 +2274,7 @@ public class UserManager { @RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) - public boolean hasUserRestrictionForUser(@NonNull String restrictionKey, + public boolean hasUserRestrictionForUser(@NonNull @UserRestrictionKey String restrictionKey, @NonNull UserHandle userHandle) { try { return mService.hasUserRestriction(restrictionKey, userHandle.getIdentifier()); @@ -2207,7 +2287,7 @@ public class UserManager { * @hide * Returns whether any user on the device has the given user restriction set. */ - public boolean hasUserRestrictionOnAnyUser(String restrictionKey) { + public boolean hasUserRestrictionOnAnyUser(@UserRestrictionKey String restrictionKey) { try { return mService.hasUserRestrictionOnAnyUser(restrictionKey); } catch (RemoteException re) { diff --git a/core/java/android/os/connectivity/WifiActivityEnergyInfo.java b/core/java/android/os/connectivity/WifiActivityEnergyInfo.java index 7db003d9853c..664b6c87d339 100644 --- a/core/java/android/os/connectivity/WifiActivityEnergyInfo.java +++ b/core/java/android/os/connectivity/WifiActivityEnergyInfo.java @@ -19,9 +19,13 @@ package android.os.connectivity; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.app.ActivityThread; +import android.content.Context; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.os.PowerProfile; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -72,7 +76,6 @@ public final class WifiActivityEnergyInfo implements Parcelable { * @param scanDurationMillis Cumulative milliseconds when radio is awake due to scan. * @param idleDurationMillis Cumulative milliseconds when radio is awake but not transmitting or * receiving. - * @param energyUsedMicroJoules Cumulative energy consumed by Wifi, in microjoules. */ public WifiActivityEnergyInfo( long timeSinceBootMillis, @@ -80,14 +83,33 @@ public final class WifiActivityEnergyInfo implements Parcelable { long txDurationMillis, long rxDurationMillis, long scanDurationMillis, - long idleDurationMillis, - long energyUsedMicroJoules) { + long idleDurationMillis) { mTimeSinceBootMillis = timeSinceBootMillis; mStackState = stackState; mControllerTxDurationMillis = txDurationMillis; mControllerRxDurationMillis = rxDurationMillis; mControllerScanDurationMillis = scanDurationMillis; mControllerIdleDurationMillis = idleDurationMillis; + + final Context context = ActivityThread.currentActivityThread().getSystemContext(); + if (context == null) { + mControllerEnergyUsedMicroJoules = 0L; + return; + } + // Calculate energy used using PowerProfile. + PowerProfile powerProfile = new PowerProfile(context); + final double rxIdleCurrent = powerProfile.getAveragePower( + PowerProfile.POWER_WIFI_CONTROLLER_IDLE); + final double rxCurrent = powerProfile.getAveragePower( + PowerProfile.POWER_WIFI_CONTROLLER_RX); + final double txCurrent = powerProfile.getAveragePower( + PowerProfile.POWER_WIFI_CONTROLLER_TX); + final double voltage = powerProfile.getAveragePower( + PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0; + final long energyUsedMicroJoules = (long) ((mControllerTxDurationMillis * txCurrent + + mControllerRxDurationMillis * rxCurrent + + mControllerIdleDurationMillis * rxIdleCurrent) + * voltage); mControllerEnergyUsedMicroJoules = energyUsedMicroJoules; } @@ -113,9 +135,8 @@ public final class WifiActivityEnergyInfo implements Parcelable { long rxTime = in.readLong(); long scanTime = in.readLong(); long idleTime = in.readLong(); - long energyUsed = in.readLong(); return new WifiActivityEnergyInfo(timestamp, stackState, - txTime, rxTime, scanTime, idleTime, energyUsed); + txTime, rxTime, scanTime, idleTime); } public WifiActivityEnergyInfo[] newArray(int size) { return new WifiActivityEnergyInfo[size]; @@ -130,7 +151,6 @@ public final class WifiActivityEnergyInfo implements Parcelable { out.writeLong(mControllerRxDurationMillis); out.writeLong(mControllerScanDurationMillis); out.writeLong(mControllerIdleDurationMillis); - out.writeLong(mControllerEnergyUsedMicroJoules); } @Override diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index 14c299d11a94..5cac5f580af1 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -109,4 +109,13 @@ public abstract class StorageManagerInternal { */ public abstract void onAppOpsChanged(int code, int uid, @Nullable String packageName, int mode); + + /** + * Asks the StorageManager to reset all state for the provided user; this will result + * in the unmounting for all volumes of the user, and, if the user is still running, the + * volumes will be re-mounted as well. + * + * @param userId the userId for which to reset storage + */ + public abstract void resetUser(int userId); } diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index f10e184ccf5a..8bf723fa54ed 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -17,6 +17,8 @@ package android.provider; import android.accounts.Account; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; @@ -2902,6 +2904,40 @@ public final class ContactsContract { } /** + * The default value used for {@link #ACCOUNT_NAME} of raw contacts when they are inserted + * without a value for this column. + * + * <p>This account is used to identify contacts that are only stored locally in the + * contacts database instead of being associated with an {@link Account} managed by an + * installed application. + * + * <p>When this returns null then {@link #getLocalAccountType} will also return null and + * when it is non-null {@link #getLocalAccountType} will also return a non-null value. + */ + @Nullable + public static String getLocalAccountName(@NonNull Context context) { + return TextUtils.nullIfEmpty(context.getString( + com.android.internal.R.string.config_rawContactsLocalAccountName)); + } + + /** + * The default value used for {@link #ACCOUNT_TYPE} of raw contacts when they are inserted + * without a value for this column. + * + * <p>This account is used to identify contacts that are only stored locally in the + * contacts database instead of being associated with an {@link Account} managed by an + * installed application. + * + * <p>When this returns null then {@link #getLocalAccountName} will also return null and + * when it is non-null {@link #getLocalAccountName} will also return a non-null value. + */ + @Nullable + public static String getLocalAccountType(@NonNull Context context) { + return TextUtils.nullIfEmpty(context.getString( + com.android.internal.R.string.config_rawContactsLocalAccountType)); + } + + /** * A sub-directory of a single raw contact that contains all of its * {@link ContactsContract.Data} rows. To access this directory * append {@link Data#CONTENT_DIRECTORY} to the raw contact URI. diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 2c53025da350..2fa3386bccb8 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -27,6 +27,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.app.Activity; @@ -62,6 +63,7 @@ import android.os.UserManager; import android.os.storage.StorageManager; import android.os.storage.StorageVolume; import android.os.storage.VolumeInfo; +import android.os.storage.VolumeRecord; import android.service.media.CameraPrewarmService; import android.text.TextUtils; import android.text.format.DateUtils; @@ -157,6 +159,8 @@ public final class MediaStore { public static final String SCAN_FILE_CALL = "scan_file"; /** {@hide} */ public static final String SCAN_VOLUME_CALL = "scan_volume"; + /** {@hide} */ + public static final String SUICIDE_CALL = "suicide"; /** * Extra used with {@link #SCAN_FILE_CALL} or {@link #SCAN_VOLUME_CALL} to indicate that @@ -1590,31 +1594,41 @@ public final class MediaStore { /** * Constant for the {@link #MEDIA_TYPE} column indicating that file - * is not an audio, image, video or playlist file. + * is not an audio, image, video, playlist, or subtitles file. */ public static final int MEDIA_TYPE_NONE = 0; /** - * Constant for the {@link #MEDIA_TYPE} column indicating that file is an image file. + * Constant for the {@link #MEDIA_TYPE} column indicating that file + * is an image file. */ public static final int MEDIA_TYPE_IMAGE = 1; /** - * Constant for the {@link #MEDIA_TYPE} column indicating that file is an audio file. + * Constant for the {@link #MEDIA_TYPE} column indicating that file + * is an audio file. */ public static final int MEDIA_TYPE_AUDIO = 2; /** - * Constant for the {@link #MEDIA_TYPE} column indicating that file is a video file. + * Constant for the {@link #MEDIA_TYPE} column indicating that file + * is a video file. */ public static final int MEDIA_TYPE_VIDEO = 3; /** - * Constant for the {@link #MEDIA_TYPE} column indicating that file is a playlist file. + * Constant for the {@link #MEDIA_TYPE} column indicating that file + * is a playlist file. */ public static final int MEDIA_TYPE_PLAYLIST = 4; /** + * Constant for the {@link #MEDIA_TYPE} column indicating that file + * is a subtitles or lyrics file. + */ + public static final int MEDIA_TYPE_SUBTITLE = 5; + + /** * Column indicating if the file is part of Downloads collection. * @hide */ @@ -3603,6 +3617,43 @@ public final class MediaStore { } /** + * Return list of all specific volume names that have recently been part of + * {@link #VOLUME_EXTERNAL}. + * <p> + * This includes both currently mounted volumes <em>and</em> recently + * mounted (but currently unmounted) volumes. Any indexed metadata for these + * volumes is preserved to optimize the speed of remounting at a later time. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) + public static @NonNull Set<String> getRecentExternalVolumeNames(@NonNull Context context) { + final StorageManager sm = context.getSystemService(StorageManager.class); + + // We always have primary storage + final Set<String> volumeNames = new ArraySet<>(); + volumeNames.add(VOLUME_EXTERNAL_PRIMARY); + + final long lastWeek = System.currentTimeMillis() - DateUtils.WEEK_IN_MILLIS; + for (VolumeRecord rec : sm.getVolumeRecords()) { + // Skip volumes without valid UUIDs + if (TextUtils.isEmpty(rec.fsUuid)) continue; + + final VolumeInfo vi = sm.findVolumeByUuid(rec.fsUuid); + if (vi != null && vi.isVisibleForUser(UserHandle.myUserId()) + && vi.isMountedReadable()) { + // We're mounted right now + volumeNames.add(rec.getNormalizedFsUuid()); + } else if (rec.lastSeenMillis > 0 && rec.lastSeenMillis < lastWeek) { + // We're not mounted right now, but we've been seen recently + volumeNames.add(rec.getNormalizedFsUuid()); + } + } + return volumeNames; + } + + /** * Return the volume name that the given {@link Uri} references. */ public static @NonNull String getVolumeName(@NonNull Uri uri) { @@ -3701,6 +3752,8 @@ public final class MediaStore { * @hide */ @TestApi + @SystemApi + @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static @NonNull Collection<File> getVolumeScanPaths(@NonNull String volumeName) throws FileNotFoundException { if (TextUtils.isEmpty(volumeName)) { @@ -3929,6 +3982,16 @@ public final class MediaStore { } /** @hide */ + public static void suicide(Context context) { + final ContentResolver resolver = context.getContentResolver(); + try (ContentProviderClient client = resolver + .acquireUnstableContentProviderClient(AUTHORITY)) { + client.call(SUICIDE_CALL, null, null); + } catch (Exception ignored) { + } + } + + /** @hide */ @TestApi public static Uri scanFile(Context context, File file) { return scan(context, SCAN_FILE_CALL, file, false); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ad8d55313795..165c2843301c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -648,6 +648,22 @@ public final class Settings { "android.settings.NIGHT_DISPLAY_SETTINGS"; /** + * Activity Action: Show settings to allow configuration of Dark theme. + * <p> + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_DARK_THEME_SETTINGS = + "android.settings.DARK_THEME_SETTINGS"; + + /** * Activity Action: Show settings to allow configuration of locale. * <p> * In some cases, a matching Activity may not exist, so ensure you diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 22f90f62b114..70c8e5d311bd 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -4837,4 +4837,23 @@ public final class Telephony { public static final Uri CONTENT_URI = Uri.parse("content://carrier_id/all"); } } + + /** + * Contains SIM Information + * @hide + */ + @SystemApi + public static final class SimInfo { + /** + * Not instantiable. + * @hide + */ + private SimInfo() {} + + /** + * The {@code content://} style URI for this provider. + */ + @NonNull + public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo"); + } } diff --git a/core/java/android/service/incremental/IncrementalDataLoaderService.java b/core/java/android/service/incremental/IncrementalDataLoaderService.java new file mode 100644 index 000000000000..c4a06c8f53db --- /dev/null +++ b/core/java/android/service/incremental/IncrementalDataLoaderService.java @@ -0,0 +1,563 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.incremental; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.Service; +import android.content.Intent; +import android.content.pm.IDataLoader; +import android.content.pm.IDataLoaderStatusListener; +import android.content.pm.InstallationFile; +import android.os.Bundle; +import android.os.IBinder; +import android.os.incremental.IncrementalDataLoaderParams; +import android.os.incremental.IncrementalDataLoaderParamsParcel; +import android.os.incremental.IncrementalFileSystemControlParcel; +import android.os.incremental.NamedParcelFileDescriptor; +import android.util.Slog; + +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Collection; +import java.util.List; + + +/** + * The base class for implementing data loader service to control data loaders. Expecting + * Incremental Service to bind to a children class of this. + * + * @hide + * + * Hide for now, should be @SystemApi + * TODO(b/136132412): update with latest API design + */ +public abstract class IncrementalDataLoaderService extends Service { + private static final String TAG = "IncrementalDataLoaderService"; + private final DataLoaderBinderService mBinder = new DataLoaderBinderService(); + + public static final int DATA_LOADER_READY = + IDataLoaderStatusListener.DATA_LOADER_READY; + public static final int DATA_LOADER_NOT_READY = + IDataLoaderStatusListener.DATA_LOADER_NOT_READY; + public static final int DATA_LOADER_RUNNING = + IDataLoaderStatusListener.DATA_LOADER_RUNNING; + public static final int DATA_LOADER_STOPPED = + IDataLoaderStatusListener.DATA_LOADER_STOPPED; + public static final int DATA_LOADER_SLOW_CONNECTION = + IDataLoaderStatusListener.DATA_LOADER_SLOW_CONNECTION; + public static final int DATA_LOADER_NO_CONNECTION = + IDataLoaderStatusListener.DATA_LOADER_NO_CONNECTION; + public static final int DATA_LOADER_CONNECTION_OK = + IDataLoaderStatusListener.DATA_LOADER_CONNECTION_OK; + + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"DATA_LOADER_"}, value = { + DATA_LOADER_READY, + DATA_LOADER_NOT_READY, + DATA_LOADER_RUNNING, + DATA_LOADER_STOPPED, + DATA_LOADER_SLOW_CONNECTION, + DATA_LOADER_NO_CONNECTION, + DATA_LOADER_CONNECTION_OK + }) + public @interface DataLoaderStatus { + } + + /** + * Incremental FileSystem block size. + **/ + public static final int BLOCK_SIZE = 4096; + + /** + * Data compression types + */ + public static final int COMPRESSION_NONE = 0; + public static final int COMPRESSION_LZ4 = 1; + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({COMPRESSION_NONE, COMPRESSION_LZ4}) + public @interface CompressionType { + } + + /** + * Managed DataLoader interface. Each instance corresponds to a single Incremental File System + * instance. + */ + public abstract static class DataLoader { + /** + * A virtual constructor used to do simple initialization. Not ready to serve any data yet. + * All heavy-lifting has to be done in onStart. + * + * @param params Data loader configuration parameters. + * @param connector IncFS API wrapper. + * @param listener Used for reporting internal state to IncrementalService. + * @return True if initialization of a Data Loader was successful. False will be reported to + * IncrementalService and can cause an unmount of an IFS instance. + */ + public abstract boolean onCreate(@NonNull IncrementalDataLoaderParams params, + @NonNull FileSystemConnector connector, + @NonNull StatusListener listener); + + /** + * Start the data loader. After this method returns data loader is considered to be ready to + * receive callbacks from IFS, supply data via connector and send status updates via + * callbacks. + * + * @return True if Data Loader was able to start. False will be reported to + * IncrementalService and can cause an unmount of an IFS instance. + */ + public abstract boolean onStart(); + + /** + * Stop the data loader. Use to stop any additional threads and free up resources. Data + * loader is not longer responsible for supplying data. Start/Stop pair can be called + * multiple times e.g. if IFS detects corruption and data needs to be re-loaded. + */ + public abstract void onStop(); + + /** + * Virtual destructor. Use to cleanup all internal state. After this method returns, the + * data loader can no longer use connector or callbacks. For any additional operations with + * this instance of IFS a new DataLoader will be created using createDataLoader method. + */ + public abstract void onDestroy(); + + /** + * IFS reports a pending read each time the page needs to be loaded, e.g. missing. + * + * @param pendingReads array of blocks to load. + * + * TODO(b/136132412): avoid using collections + */ + public abstract void onPendingReads( + @NonNull Collection<FileSystemConnector.PendingReadInfo> pendingReads); + + /** + * IFS tracks all reads and reports them using onPageReads. + * + * @param reads array of blocks. + * + * TODO(b/136132412): avoid using collections + */ + public abstract void onPageReads(@NonNull Collection<FileSystemConnector.ReadInfo> reads); + + /** + * IFS informs data loader that a new file has been created. + * <p> + * This can be used to prepare the data loader before it starts loading data. For example, + * the data loader can keep a list of newly created files, so that it knows what files to + * download from the server. + * + * @param inode The inode value of the new file. + * @param metadata The metadata of the new file. + */ + public abstract void onFileCreated(long inode, byte[] metadata); + } + + /** + * DataLoader factory method. + * + * @return An instance of a DataLoader. + */ + public abstract @Nullable DataLoader onCreateDataLoader(); + + /** + * @hide + */ + public final @NonNull IBinder onBind(@NonNull Intent intent) { + return (IBinder) mBinder; + } + + private class DataLoaderBinderService extends IDataLoader.Stub { + private int mId; + + @Override + public void create(int id, @NonNull Bundle options, + @NonNull IDataLoaderStatusListener listener) + throws IllegalArgumentException, RuntimeException { + mId = id; + final IncrementalDataLoaderParamsParcel params = options.getParcelable("params"); + if (params == null) { + throw new IllegalArgumentException("Must specify Incremental data loader params"); + } + final IncrementalFileSystemControlParcel control = + options.getParcelable("control"); + if (control == null) { + throw new IllegalArgumentException("Must specify Incremental control parcel"); + } + mStatusListener = listener; + try { + if (!nativeCreateDataLoader(id, control, params, listener)) { + Slog.e(TAG, "Failed to create native loader for " + mId); + } + } catch (Exception ex) { + destroy(); + throw new RuntimeException(ex); + } finally { + // Closing FDs. + if (control.cmd != null) { + try { + control.cmd.close(); + } catch (IOException e) { + Slog.e(TAG, "Failed to close IncFs CMD file descriptor " + e); + } + } + if (control.log != null) { + try { + control.log.close(); + } catch (IOException e) { + Slog.e(TAG, "Failed to close IncFs LOG file descriptor " + e); + } + } + NamedParcelFileDescriptor[] fds = params.dynamicArgs; + for (NamedParcelFileDescriptor nfd : fds) { + try { + nfd.fd.close(); + } catch (IOException e) { + Slog.e(TAG, + "Failed to close DynamicArgs parcel file descriptor " + e); + } + } + } + } + + @Override + public void start(List<InstallationFile> fileInfos) { + if (!nativeStartDataLoader(mId)) { + Slog.e(TAG, "Failed to start loader: loader not found for " + mId); + } + } + + @Override + public void stop() { + if (!nativeStopDataLoader(mId)) { + Slog.w(TAG, "Failed to stop loader: loader not found for " + mId); + } + } + + @Override + public void destroy() { + if (!nativeDestroyDataLoader(mId)) { + Slog.w(TAG, "Failed to destroy loader: loader not found for " + mId); + } + } + + @Override + // TODO(b/136132412): remove this + public void onFileCreated(long inode, byte[] metadata) { + if (!nativeOnFileCreated(mId, inode, metadata)) { + Slog.w(TAG, "Failed to handle onFileCreated for storage:" + mId + + " inode:" + inode); + } + } + } + + /** + * IncFs API wrapper for writing pages and getting page missing info. Non-hidden methods are + * expected to be called by the IncrementalDataLoaderService implemented by developers. + * + * @hide + * + * TODO(b/136132412) Should be @SystemApi + */ + public static final class FileSystemConnector { + /** + * Defines a block address. A block is the unit of data chunk that IncFs operates with. + * + * @hide + */ + public static class BlockAddress { + /** + * Linux inode uniquely identifies file within a single IFS instance. + */ + private final long mFileIno; + /** + * Index of a 4K block within a file. + */ + private final int mBlockIndex; + + public BlockAddress(long fileIno, int blockIndex) { + this.mFileIno = fileIno; + this.mBlockIndex = blockIndex; + } + + public long getFileIno() { + return mFileIno; + } + + public int getBlockIndex() { + return mBlockIndex; + } + } + + /** + * A block is the unit of data chunk that IncFs operates with. + * + * @hide + */ + public static class Block extends BlockAddress { + /** + * Data content of the block. + */ + private final @NonNull byte[] mDataBytes; + + public Block(long fileIno, int blockIndex, @NonNull byte[] dataBytes) { + super(fileIno, blockIndex); + this.mDataBytes = dataBytes; + } + } + + /** + * Defines a page/block inside a file. + */ + public static class DataBlock extends Block { + /** + * Compression type of the data block. + */ + private final @CompressionType int mCompressionType; + + public DataBlock(long fileIno, int blockIndex, @NonNull byte[] dataBytes, + @CompressionType int compressionType) { + super(fileIno, blockIndex, dataBytes); + this.mCompressionType = compressionType; + } + } + + /** + * Defines a hash block for a certain file. A hash block index is the index in an array of + * hashes which is the 1-d representation of the hash tree. One DataBlock might be + * associated with multiple HashBlocks. + */ + public static class HashBlock extends Block { + public HashBlock(long fileIno, int blockIndex, @NonNull byte[] dataBytes) { + super(fileIno, blockIndex, dataBytes); + } + } + + /** + * Information about a page that is pending to be read. + */ + public static class PendingReadInfo extends BlockAddress { + PendingReadInfo(long fileIno, int blockIndex) { + super(fileIno, blockIndex); + } + } + + /** + * Information about a page that is read. + */ + public static class ReadInfo extends BlockAddress { + /** + * A monotonically increasing read timestamp. + */ + private final long mTimePoint; + /** + * Number of blocks read starting from blockIndex. + */ + private final int mBlockCount; + + ReadInfo(long timePoint, long fileIno, int firstBlockIndex, int blockCount) { + super(fileIno, firstBlockIndex); + this.mTimePoint = timePoint; + this.mBlockCount = blockCount; + } + + public long getTimePoint() { + return mTimePoint; + } + + public int getBlockCount() { + return mBlockCount; + } + } + + /** + * Defines the dynamic information about an IncFs file. + */ + public static class FileInfo { + /** + * BitSet to show if any block is available at each block index. + */ + private final @NonNull + byte[] mBlockBitmap; + + /** + * @hide + */ + public FileInfo(@NonNull byte[] blockBitmap) { + this.mBlockBitmap = blockBitmap; + } + } + + /** + * Creates a wrapper for a native instance. + */ + FileSystemConnector(long nativeInstance) { + mNativeInstance = nativeInstance; + } + + /** + * Checks whether a range in a file if loaded. + * + * @param node inode of the file. + * @param start The starting offset of the range. + * @param end The ending offset of the range. + * @return True if the file is fully loaded. + */ + public boolean isFileRangeLoaded(long node, long start, long end) { + return nativeIsFileRangeLoadedNode(mNativeInstance, node, start, end); + } + + /** + * Gets the metadata of a file. + * + * @param node inode of the file. + * @return The metadata object. + */ + @NonNull + public byte[] getFileMetadata(long node) throws IOException { + final byte[] metadata = nativeGetFileMetadataNode(mNativeInstance, node); + if (metadata == null || metadata.length == 0) { + throw new IOException( + "IncrementalFileSystem failed to obtain metadata for node: " + node); + } + return metadata; + } + + /** + * Gets the dynamic information of a file, such as page bitmaps. Can be used to get missing + * page indices by the FileSystemConnector. + * + * @param node inode of the file. + * @return Dynamic file info. + */ + @NonNull + public FileInfo getDynamicFileInfo(long node) throws IOException { + final byte[] blockBitmap = nativeGetFileInfoNode(mNativeInstance, node); + if (blockBitmap == null || blockBitmap.length == 0) { + throw new IOException( + "IncrementalFileSystem failed to obtain dynamic file info for node: " + + node); + } + return new FileInfo(blockBitmap); + } + + /** + * Writes a page's data and/or hashes. + * + * @param dataBlocks the DataBlock objects that contain data block index and data bytes. + * @param hashBlocks the HashBlock objects that contain hash indices and hash bytes. + * + * TODO(b/136132412): change API to avoid dynamic allocation of data block objects + */ + public void writeMissingData(@NonNull DataBlock[] dataBlocks, + @Nullable HashBlock[] hashBlocks) throws IOException { + if (!nativeWriteMissingData(mNativeInstance, dataBlocks, hashBlocks)) { + throw new IOException("IncrementalFileSystem failed to write missing data."); + } + } + + /** + * Writes the signer block of a file. Expecting the connector to call this when it got + * signing data from data loader. + * + * @param node the file to be written to. + * @param signerData the raw signer data byte array. + */ + public void writeSignerData(long node, @NonNull byte[] signerData) + throws IOException { + if (!nativeWriteSignerDataNode(mNativeInstance, node, signerData)) { + throw new IOException( + "IncrementalFileSystem failed to write signer data of node " + node); + } + } + + private final long mNativeInstance; + } + + /** + * Wrapper for native reporting DataLoader statuses. + * + * @hide + * + * TODO(b/136132412) Should be @SystemApi + */ + public static final class StatusListener { + /** + * Creates a wrapper for a native instance. + * + * @hide + */ + StatusListener(long nativeInstance) { + mNativeInstance = nativeInstance; + } + + /** + * Report the status of DataLoader. Used for system-wide notifications e.g., disabling + * applications which rely on this data loader to function properly. + * + * @param status status to report. + * @return True if status was reported successfully. + */ + public boolean onStatusChanged(@DataLoaderStatus int status) { + return nativeReportStatus(mNativeInstance, status); + } + + private final long mNativeInstance; + } + + private IDataLoaderStatusListener mStatusListener = null; + + /* Native methods */ + private native boolean nativeCreateDataLoader(int storageId, + @NonNull IncrementalFileSystemControlParcel control, + @NonNull IncrementalDataLoaderParamsParcel params, + IDataLoaderStatusListener listener); + + private native boolean nativeStartDataLoader(int storageId); + + private native boolean nativeStopDataLoader(int storageId); + + private native boolean nativeDestroyDataLoader(int storageId); + + private static native boolean nativeOnFileCreated(int storageId, + long inode, byte[] metadata); + + private static native boolean nativeIsFileRangeLoadedNode( + long nativeInstance, long node, long start, long end); + + private static native boolean nativeWriteMissingData( + long nativeInstance, FileSystemConnector.DataBlock[] dataBlocks, + FileSystemConnector.HashBlock[] hashBlocks); + + private static native boolean nativeWriteSignerDataNode( + long nativeInstance, long node, byte[] signerData); + + private static native byte[] nativeGetFileMetadataNode( + long nativeInstance, long node); + + private static native byte[] nativeGetFileInfoNode( + long nativeInstance, long node); + + private static native boolean nativeReportStatus(long nativeInstance, int status); +} diff --git a/core/java/android/telephony/CellBroadcastIntents.java b/core/java/android/telephony/CellBroadcastIntents.java index 4474f3ecc620..8446253c6302 100644 --- a/core/java/android/telephony/CellBroadcastIntents.java +++ b/core/java/android/telephony/CellBroadcastIntents.java @@ -26,7 +26,6 @@ import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.os.UserHandle; -import android.util.Log; /** * A static helper class used to send Intents with prepopulated flags. @@ -75,20 +74,20 @@ public class CellBroadcastIntents { @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler, int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) { - Log.d(LOG_TAG, "sendOrderedBroadcastForBackgroundReceivers intent=" + intent.getAction()); int status = context.checkCallingOrSelfPermission( "android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"); if (status == PackageManager.PERMISSION_DENIED) { throw new SecurityException( "Caller does not have permission to send broadcast for background receivers"); } - intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + Intent backgroundIntent = new Intent(intent); + backgroundIntent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); if (user != null) { - context.createContextAsUser(user, 0).sendOrderedBroadcast(intent, receiverPermission, - receiverAppOp, resultReceiver, scheduler, initialCode, initialData, - initialExtras); + context.createContextAsUser(user, 0).sendOrderedBroadcast(backgroundIntent, + receiverPermission, receiverAppOp, resultReceiver, scheduler, initialCode, + initialData, initialExtras); } else { - context.sendOrderedBroadcast(intent, receiverPermission, + context.sendOrderedBroadcast(backgroundIntent, receiverPermission, receiverAppOp, resultReceiver, scheduler, initialCode, initialData, initialExtras); } diff --git a/telephony/java/android/telephony/SubscriptionPlan.aidl b/core/java/android/telephony/SubscriptionPlan.aidl index 655df3a71b3d..655df3a71b3d 100755 --- a/telephony/java/android/telephony/SubscriptionPlan.aidl +++ b/core/java/android/telephony/SubscriptionPlan.aidl diff --git a/telephony/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java index 28a5c2086ede..28a5c2086ede 100644 --- a/telephony/java/android/telephony/SubscriptionPlan.java +++ b/core/java/android/telephony/SubscriptionPlan.java diff --git a/core/java/android/text/AlteredCharSequence.java b/core/java/android/text/AlteredCharSequence.java index 4cc71fd28e4b..971a47dba6e8 100644 --- a/core/java/android/text/AlteredCharSequence.java +++ b/core/java/android/text/AlteredCharSequence.java @@ -16,12 +16,14 @@ package android.text; -// XXX should this really be in the public API at all? /** * An AlteredCharSequence is a CharSequence that is largely mirrored from * another CharSequence, except that a specified range of characters are * mirrored from a different char array instead. + * + * @deprecated The functionality this class offers is easily implemented outside the framework. */ +@Deprecated public class AlteredCharSequence implements CharSequence, GetChars { diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java index 3a1df3ec861e..6a6bccf7052a 100644 --- a/core/java/android/util/LocalLog.java +++ b/core/java/android/util/LocalLog.java @@ -17,9 +17,11 @@ package android.util; import android.annotation.UnsupportedAppUsage; +import android.os.SystemClock; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.time.Instant; import java.time.LocalDateTime; import java.util.ArrayDeque; import java.util.Deque; @@ -33,10 +35,22 @@ public final class LocalLog { private final Deque<String> mLog; private final int mMaxLines; + /** + * {@code true} to use log timestamps expressed in local date/time, {@code false} to use log + * timestamped expressed with the elapsed realtime clock and UTC system clock. {@code false} is + * useful when logging behavior that modifies device time zone or system clock. + */ + private final boolean mUseLocalTimestamps; + @UnsupportedAppUsage public LocalLog(int maxLines) { + this(maxLines, true /* useLocalTimestamps */); + } + + public LocalLog(int maxLines, boolean useLocalTimestamps) { mMaxLines = Math.max(0, maxLines); mLog = new ArrayDeque<>(mMaxLines); + mUseLocalTimestamps = useLocalTimestamps; } @UnsupportedAppUsage @@ -44,7 +58,14 @@ public final class LocalLog { if (mMaxLines <= 0) { return; } - append(String.format("%s - %s", LocalDateTime.now(), msg)); + final String logLine; + if (mUseLocalTimestamps) { + logLine = String.format("%s - %s", LocalDateTime.now(), msg); + } else { + logLine = String.format( + "%s / %s - %s", SystemClock.elapsedRealtime(), Instant.now(), msg); + } + append(logLine); } private synchronized void append(String logLine) { diff --git a/core/java/android/util/StatsEvent.java b/core/java/android/util/StatsEvent.java index 0a4069d15706..c7659457bdf9 100644 --- a/core/java/android/util/StatsEvent.java +++ b/core/java/android/util/StatsEvent.java @@ -20,8 +20,6 @@ import static java.nio.charset.StandardCharsets.UTF_8; import android.annotation.NonNull; import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; import android.os.SystemClock; import com.android.internal.annotations.GuardedBy; @@ -33,18 +31,27 @@ import com.android.internal.annotations.VisibleForTesting; * * <p>Usage:</p> * <pre> + * // Pushed event * StatsEvent statsEvent = StatsEvent.newBuilder() * .setAtomId(atomId) * .writeBoolean(false) * .writeString("annotated String field") * .addBooleanAnnotation(annotationId, true) + * .usePooledBuffer() * .build(); - * * StatsLog.write(statsEvent); + * + * // Pulled event + * StatsEvent statsEvent = StatsEvent.newBuilder() + * .setAtomId(atomId) + * .writeBoolean(false) + * .writeString("annotated String field") + * .addBooleanAnnotation(annotationId, true) + * .build(); * </pre> * @hide **/ -public final class StatsEvent implements Parcelable { +public final class StatsEvent { // Type Ids. /** * @hide @@ -212,12 +219,15 @@ public final class StatsEvent implements Parcelable { private static final int MAX_PAYLOAD_SIZE = LOGGER_ENTRY_MAX_PAYLOAD - 4; private final int mAtomId; - private final Buffer mBuffer; + private final byte[] mPayload; + private Buffer mBuffer; private final int mNumBytes; - private StatsEvent(final int atomId, @NonNull final Buffer buffer, final int numBytes) { + private StatsEvent(final int atomId, @Nullable final Buffer buffer, + @NonNull final byte[] payload, final int numBytes) { mAtomId = atomId; mBuffer = buffer; + mPayload = payload; mNumBytes = numBytes; } @@ -245,7 +255,7 @@ public final class StatsEvent implements Parcelable { **/ @NonNull public byte[] getBytes() { - return mBuffer.getBytes(); + return mPayload; } /** @@ -258,45 +268,16 @@ public final class StatsEvent implements Parcelable { } /** - * Recycle this StatsEvent object. + * Recycle resources used by this StatsEvent object. + * No actions should be taken on this StatsEvent after release() is called. **/ public void release() { - mBuffer.release(); - } - - /** - * Boilerplate for Parcel. - */ - public static final @NonNull Parcelable.Creator<StatsEvent> CREATOR = - new Parcelable.Creator<StatsEvent>() { - public StatsEvent createFromParcel(Parcel in) { - // Purposefully leaving this method not implemented. - throw new RuntimeException("Not implemented"); - } - - public StatsEvent[] newArray(int size) { - // Purposefully leaving this method not implemented. - throw new RuntimeException("Not implemented"); - } - }; - - /** - * Boilerplate for Parcel. - */ - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mAtomId); - out.writeInt(getNumBytes()); - out.writeByteArray(getBytes()); - } - - /** - * Boilerplate for Parcel. - */ - public int describeContents() { - return 0; + if (mBuffer != null) { + mBuffer.release(); + mBuffer = null; + } } - /** * Builder for constructing a StatsEvent object. * @@ -315,7 +296,18 @@ public final class StatsEvent implements Parcelable { * optional string field3 = 3 [(annotation1) = true]; * } * - * // StatsEvent construction. + * // StatsEvent construction for pushed event. + * StatsEvent.newBuilder() + * StatsEvent statsEvent = StatsEvent.newBuilder() + * .setAtomId(atomId) + * .writeInt(3) // field1 + * .writeLong(8L) // field2 + * .writeString("foo") // field 3 + * .addBooleanAnnotation(annotation1Id, true) + * .usePooledBuffer() + * .build(); + * + * // StatsEvent construction for pulled event. * StatsEvent.newBuilder() * StatsEvent statsEvent = StatsEvent.newBuilder() * .setAtomId(atomId) @@ -341,6 +333,7 @@ public final class StatsEvent implements Parcelable { private byte mLastType; private int mNumElements; private int mErrorMask; + private boolean mUsePooledBuffer = false; private Builder(final Buffer buffer) { mBuffer = buffer; @@ -604,6 +597,17 @@ public final class StatsEvent implements Parcelable { } /** + * Indicates to reuse Buffer's byte array as the underlying payload in StatsEvent. + * This should be called for pushed events to reduce memory allocations and garbage + * collections. + **/ + @NonNull + public Builder usePooledBuffer() { + mUsePooledBuffer = true; + return this; + } + + /** * Builds a StatsEvent object with values entered in this Builder. **/ @NonNull @@ -634,7 +638,18 @@ public final class StatsEvent implements Parcelable { size = mPos; } - return new StatsEvent(mAtomId, mBuffer, size); + if (mUsePooledBuffer) { + return new StatsEvent(mAtomId, mBuffer, mBuffer.getBytes(), size); + } else { + // Create a copy of the buffer with the required number of bytes. + final byte[] payload = new byte[size]; + System.arraycopy(mBuffer.getBytes(), 0, payload, 0, size); + + // Return Buffer instance to the pool. + mBuffer.release(); + + return new StatsEvent(mAtomId, null, payload, size); + } } private void writeTypeId(final byte typeId) { diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java index 64e15cfb7948..9ac4cf267b47 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -179,6 +179,8 @@ public final class StatsLog extends StatsLogInternal { * @param rollbackType state of the rollback. * @param packageName package name being rolled back. * @param packageVersionCode version of the package being rolled back. + * @param rollbackReason reason the package is being rolled back. + * @param failingPackageName the package name causing the failure. * * @return True if the log request was sent to statsd. * @@ -186,7 +188,7 @@ public final class StatsLog extends StatsLogInternal { */ @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS}) public static boolean logWatchdogRollbackOccurred(int rollbackType, String packageName, - long packageVersionCode) { + long packageVersionCode, int rollbackReason, String failingPackageName) { synchronized (sLogLock) { try { IStatsManager service = getIStatsManagerLocked(); @@ -198,7 +200,7 @@ public final class StatsLog extends StatsLogInternal { } service.sendWatchdogRollbackOccurredAtom(rollbackType, packageName, - packageVersionCode); + packageVersionCode, rollbackReason, failingPackageName); return true; } catch (RemoteException e) { sService = null; @@ -246,12 +248,15 @@ public final class StatsLog extends StatsLogInternal { /** * Write an event to stats log using the raw format encapsulated in StatsEvent. + * After writing to stats log, release() is called on the StatsEvent object. + * No further action should be taken on the StatsEvent object following this call. * * @param statsEvent The StatsEvent object containing the encoded buffer of data to write. * @hide */ public static void write(@NonNull final StatsEvent statsEvent) { writeImpl(statsEvent.getBytes(), statsEvent.getNumBytes(), statsEvent.getAtomId()); + statsEvent.release(); } private static void enforceDumpCallingPermission(Context context) { diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 03e68b0058b2..ba2509302094 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -1525,5 +1525,14 @@ public final class Display { public int describeContents() { return 0; } + + @Override + public String toString() { + return "HdrCapabilities{" + + "mSupportedHdrTypes=" + Arrays.toString(mSupportedHdrTypes) + + ", mMaxLuminance=" + mMaxLuminance + + ", mMaxAverageLuminance=" + mMaxAverageLuminance + + ", mMinLuminance=" + mMinLuminance + '}'; + } } } diff --git a/core/java/android/view/DisplayAddress.java b/core/java/android/view/DisplayAddress.java index c8b7e25e59fb..e0d9a4dd1df0 100644 --- a/core/java/android/view/DisplayAddress.java +++ b/core/java/android/view/DisplayAddress.java @@ -41,6 +41,18 @@ public abstract class DisplayAddress implements Parcelable { } /** + * Creates an address for a physical display given its port and model. + * + * @param port A port in the range [0, 255] interpreted as signed. + * @param model A positive integer, or {@code null} if the model cannot be identified. + * @return The {@link Physical} address. + */ + @NonNull + public static Physical fromPortAndModel(byte port, Long model) { + return new Physical(port, model); + } + + /** * Creates an address for a network display given its MAC address. * * @param macAddress A MAC address in colon notation. @@ -64,12 +76,23 @@ public abstract class DisplayAddress implements Parcelable { public static final class Physical extends DisplayAddress { private static final long UNKNOWN_MODEL = 0; private static final int MODEL_SHIFT = 8; - private static final int PORT_MASK = 0xFF; private final long mPhysicalDisplayId; /** + * Stable display ID combining port and model. + * + * @return An ID in the range [0, 2^64) interpreted as signed. + * @see SurfaceControl#getPhysicalDisplayIds + */ + public long getPhysicalDisplayId() { + return mPhysicalDisplayId; + } + + /** * Physical port to which the display is connected. + * + * @return A port in the range [0, 255] interpreted as signed. */ public byte getPort() { return (byte) mPhysicalDisplayId; @@ -78,7 +101,7 @@ public abstract class DisplayAddress implements Parcelable { /** * Model identifier unique across manufacturers. * - * @return The model ID, or {@code null} if the model cannot be identified. + * @return A positive integer, or {@code null} if the model cannot be identified. */ @Nullable public Long getModel() { @@ -95,7 +118,7 @@ public abstract class DisplayAddress implements Parcelable { @Override public String toString() { final StringBuilder builder = new StringBuilder("{") - .append("port=").append(getPort() & PORT_MASK); + .append("port=").append(Byte.toUnsignedInt(getPort())); final Long model = getModel(); if (model != null) { @@ -119,6 +142,11 @@ public abstract class DisplayAddress implements Parcelable { mPhysicalDisplayId = physicalDisplayId; } + private Physical(byte port, Long model) { + mPhysicalDisplayId = Byte.toUnsignedLong(port) + | (model == null ? UNKNOWN_MODEL : (model << MODEL_SHIFT)); + } + public static final @NonNull Parcelable.Creator<Physical> CREATOR = new Parcelable.Creator<Physical>() { @Override diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index afa661e26d4c..3171306fc568 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1646,7 +1646,7 @@ public final class ViewRootImpl implements ViewParent, mBlastSurfaceControl, width, height); } - mBlastBufferQueue.update(mSurfaceControl, width, height); + mBlastBufferQueue.update(mBlastSurfaceControl, width, height); mTransaction.show(mBlastSurfaceControl) .reparent(mBlastSurfaceControl, mSurfaceControl) diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index cc2884075c39..843f8e33c66a 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -117,7 +117,7 @@ public final class AccessibilityManager { * Activity action: Launch UI to manage which accessibility service or feature is assigned * to the navigation bar Accessibility button. * <p> - * Input: Nothing. + * Input: {@link #EXTRA_SHORTCUT_TYPE} is the shortcut type. * </p> * <p> * Output: Nothing. @@ -130,6 +130,42 @@ public final class AccessibilityManager { "com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON"; /** + * Used as an int extra field in {@link #ACTION_CHOOSE_ACCESSIBILITY_BUTTON} intent to specify + * the shortcut type. + * + * @hide + */ + public static final String EXTRA_SHORTCUT_TYPE = + "com.android.internal.intent.extra.SHORTCUT_TYPE"; + + /** + * Used as an int value for {@link #EXTRA_SHORTCUT_TYPE} to represent the accessibility button + * shortcut type. + * + * @hide + */ + public static final int ACCESSIBILITY_BUTTON = 0; + + /** + * Used as an int value for {@link #EXTRA_SHORTCUT_TYPE} to represent hardware key shortcut, + * such as volume key button. + * + * @hide + */ + public static final int ACCESSIBILITY_SHORTCUT_KEY = 1; + + /** + * Annotations for the shortcut type. + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + ACCESSIBILITY_BUTTON, + ACCESSIBILITY_SHORTCUT_KEY + }) + public @interface ShortcutType {} + + /** * Annotations for content flag of UI. * @hide */ @@ -1242,27 +1278,28 @@ public final class AccessibilityManager { } /** - * Get the component name of the service currently assigned to the accessibility shortcut. + * Returns the list of shortcut target names currently assigned to the given shortcut. * - * @return The flattened component name + * @param shortcutType The shortcut type. + * @return The list of shortcut target names. * @hide */ @TestApi @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) - @Nullable - public String getAccessibilityShortcutService() { + @NonNull + public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) { final IAccessibilityManager service; synchronized (mLock) { service = getServiceLocked(); } if (service != null) { try { - return service.getAccessibilityShortcutService(); + return service.getAccessibilityShortcutTargets(shortcutType); } catch (RemoteException re) { re.rethrowFromSystemServer(); } } - return null; + return Collections.emptyList(); } /** diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index 023fda52a1b1..36515b3ba094 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -73,7 +73,7 @@ interface IAccessibilityManager { void performAccessibilityShortcut(); // Requires Manifest.permission.MANAGE_ACCESSIBILITY - String getAccessibilityShortcutService(); + List<String> getAccessibilityShortcutTargets(int shortcutType); // System process only boolean sendFingerprintGesture(int gestureKeyCode); diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java index 12ed4b971e83..7d1077e50258 100644 --- a/core/java/android/view/textclassifier/SelectionEvent.java +++ b/core/java/android/view/textclassifier/SelectionEvent.java @@ -161,7 +161,6 @@ public final class SelectionEvent implements Parcelable { mEntityType = in.readString(); mWidgetVersion = in.readInt() > 0 ? in.readString() : null; mPackageName = in.readString(); - mUserId = in.readInt(); mWidgetType = in.readString(); mInvocationMethod = in.readInt(); mResultId = in.readString(); @@ -175,6 +174,7 @@ public final class SelectionEvent implements Parcelable { mEnd = in.readInt(); mSmartStart = in.readInt(); mSmartEnd = in.readInt(); + mUserId = in.readInt(); } @Override @@ -188,7 +188,6 @@ public final class SelectionEvent implements Parcelable { dest.writeString(mWidgetVersion); } dest.writeString(mPackageName); - dest.writeInt(mUserId); dest.writeString(mWidgetType); dest.writeInt(mInvocationMethod); dest.writeString(mResultId); @@ -204,6 +203,7 @@ public final class SelectionEvent implements Parcelable { dest.writeInt(mEnd); dest.writeInt(mSmartStart); dest.writeInt(mSmartEnd); + dest.writeInt(mUserId); } @Override diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index c571737cec8f..7cec440dd80b 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -3473,18 +3473,10 @@ public class RemoteViews implements Parcelable, Filter { return applyAsync(context, parent, executor, listener, null); } - private CancellationSignal startTaskOnExecutor(AsyncApplyTask task, Executor executor) { - CancellationSignal cancelSignal = new CancellationSignal(); - cancelSignal.setOnCancelListener(task); - - task.executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor); - return cancelSignal; - } - /** @hide */ public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener, OnClickHandler handler) { - return startTaskOnExecutor(getAsyncApplyTask(context, parent, listener, handler), executor); + return getAsyncApplyTask(context, parent, listener, handler).startTaskOnExecutor(executor); } private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent, @@ -3495,6 +3487,7 @@ public class RemoteViews implements Parcelable, Filter { private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree> implements CancellationSignal.OnCancelListener { + final CancellationSignal mCancelSignal = new CancellationSignal(); final RemoteViews mRV; final ViewGroup mParent; final Context mContext; @@ -3545,6 +3538,7 @@ public class RemoteViews implements Parcelable, Filter { @Override protected void onPostExecute(ViewTree viewTree) { + mCancelSignal.setOnCancelListener(null); if (mError == null) { if (mListener != null) { mListener.onViewInflated(viewTree.mRoot); @@ -3581,6 +3575,13 @@ public class RemoteViews implements Parcelable, Filter { @Override public void onCancel() { cancel(true); + mCancelSignal.setOnCancelListener(null); + } + + private CancellationSignal startTaskOnExecutor(Executor executor) { + mCancelSignal.setOnCancelListener(this); + executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor); + return mCancelSignal; } } @@ -3646,8 +3647,8 @@ public class RemoteViews implements Parcelable, Filter { } } - return startTaskOnExecutor(new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(), - context, listener, handler, v), executor); + return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(), + context, listener, handler, v).startTaskOnExecutor(executor); } private void performApply(View v, ViewGroup parent, OnClickHandler handler) { diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java index 0b15cd06a7ea..3fdedc88fe53 100644 --- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java +++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java @@ -17,6 +17,7 @@ package com.android.internal.accessibility; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; import static com.android.internal.util.ArrayUtils.convertToLongArray; @@ -34,6 +35,7 @@ import android.media.AudioAttributes; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; +import android.os.Build; import android.os.Handler; import android.os.UserHandle; import android.os.Vibrator; @@ -52,11 +54,12 @@ import com.android.internal.R; import com.android.internal.util.function.pooled.PooledLambda; import java.util.Collections; +import java.util.List; import java.util.Locale; import java.util.Map; /** - * Class to help manage the accessibility shortcut + * Class to help manage the accessibility shortcut key */ public class AccessibilityShortcutController { private static final String TAG = "AccessibilityShortcutController"; @@ -66,6 +69,8 @@ public class AccessibilityShortcutController { new ComponentName("com.android.server.accessibility", "ColorInversion"); public static final ComponentName DALTONIZER_COMPONENT_NAME = new ComponentName("com.android.server.accessibility", "Daltonizer"); + public static final String MAGNIFICATION_CONTROLLER_NAME = + "com.android.server.accessibility.MagnificationController"; private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) @@ -84,26 +89,6 @@ public class AccessibilityShortcutController { public FrameworkObjectProvider mFrameworkObjectProvider = new FrameworkObjectProvider(); /** - * Get the component name string for the service or feature currently assigned to the - * accessiblity shortcut - * - * @param context A valid context - * @param userId The user ID of interest - * @return The flattened component name string of the service selected by the user, or the - * string for the default service if the user has not made a selection - */ - public static String getTargetServiceComponentNameString( - Context context, int userId) { - final String currentShortcutServiceId = Settings.Secure.getStringForUser( - context.getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, - userId); - if (currentShortcutServiceId != null) { - return currentShortcutServiceId; - } - return context.getString(R.string.config_defaultAccessibilityService); - } - - /** * @return An immutable map from dummy component names to feature info for toggling a framework * feature */ @@ -163,7 +148,7 @@ public class AccessibilityShortcutController { /** * Check if the shortcut is available. * - * @param onLockScreen Whether or not the phone is currently locked. + * @param phoneLocked Whether or not the phone is currently locked. * * @return {@code true} if the shortcut is available */ @@ -172,8 +157,7 @@ public class AccessibilityShortcutController { } public void onSettingsChanged() { - final boolean haveValidService = - !TextUtils.isEmpty(getTargetServiceComponentNameString(mContext, mUserId)); + final boolean hasShortcutTarget = hasShortcutTarget(); final ContentResolver cr = mContext.getContentResolver(); final boolean enabled = Settings.Secure.getIntForUser( cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, mUserId) == 1; @@ -183,7 +167,7 @@ public class AccessibilityShortcutController { mEnabledOnLockScreen = Settings.Secure.getIntForUser( cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, dialogAlreadyShown, mUserId) == 1; - mIsShortcutEnabled = enabled && haveValidService; + mIsShortcutEnabled = enabled && hasShortcutTarget; } /** @@ -205,7 +189,6 @@ public class AccessibilityShortcutController { vibrator.vibrate(vibePattern, -1, VIBRATION_ATTRIBUTES); } - if (dialogAlreadyShown == 0) { // The first time, we show a warning rather than toggle the service to give the user a // chance to turn off this feature before stuff gets enabled. @@ -229,32 +212,44 @@ public class AccessibilityShortcutController { mAlertDialog.dismiss(); mAlertDialog = null; } - - // Show a toast alerting the user to what's happening - final String serviceName = getShortcutFeatureDescription(false /* no summary */); - if (serviceName == null) { - Slog.e(TAG, "Accessibility shortcut set to invalid service"); - return; - } - // For accessibility services, show a toast explaining what we're doing. - final AccessibilityServiceInfo serviceInfo = getInfoForTargetService(); - if (serviceInfo != null) { - String toastMessageFormatString = mContext.getString(isServiceEnabled(serviceInfo) - ? R.string.accessibility_shortcut_disabling_service - : R.string.accessibility_shortcut_enabling_service); - String toastMessage = String.format(toastMessageFormatString, serviceName); - Toast warningToast = mFrameworkObjectProvider.makeToastFromText( - mContext, toastMessage, Toast.LENGTH_LONG); - warningToast.getWindowParams().privateFlags |= - WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; - warningToast.show(); - } - + showToast(); mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext) .performAccessibilityShortcut(); } } + /** + * Show toast if current assigned shortcut target is an accessibility service and its target + * sdk version is less than or equal to Q, or greater than Q and does not request + * accessibility button. + */ + private void showToast() { + final AccessibilityServiceInfo serviceInfo = getInfoForTargetService(); + if (serviceInfo == null) { + return; + } + final String serviceName = getShortcutFeatureDescription(/* no summary */ false); + if (serviceName == null) { + return; + } + final boolean requestA11yButton = (serviceInfo.flags + & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; + if (serviceInfo.getResolveInfo().serviceInfo.applicationInfo + .targetSdkVersion > Build.VERSION_CODES.Q && requestA11yButton) { + return; + } + // For accessibility services, show a toast explaining what we're doing. + String toastMessageFormatString = mContext.getString(isServiceEnabled(serviceInfo) + ? R.string.accessibility_shortcut_disabling_service + : R.string.accessibility_shortcut_enabling_service); + String toastMessage = String.format(toastMessageFormatString, serviceName); + Toast warningToast = mFrameworkObjectProvider.makeToastFromText( + mContext, toastMessage, Toast.LENGTH_LONG); + warningToast.getWindowParams().privateFlags |= + WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; + warningToast.show(); + } + private AlertDialog createShortcutWarningDialog(int userId) { final String serviceDescription = getShortcutFeatureDescription(true /* Include summary */); @@ -288,25 +283,21 @@ public class AccessibilityShortcutController { } private AccessibilityServiceInfo getInfoForTargetService() { - final String currentShortcutServiceString = getTargetServiceComponentNameString( - mContext, UserHandle.USER_CURRENT); - if (currentShortcutServiceString == null) { + final ComponentName targetComponentName = getShortcutTargetComponentName(); + if (targetComponentName == null) { return null; } AccessibilityManager accessibilityManager = mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext); return accessibilityManager.getInstalledServiceInfoWithComponentName( - ComponentName.unflattenFromString(currentShortcutServiceString)); + targetComponentName); } private String getShortcutFeatureDescription(boolean includeSummary) { - final String currentShortcutServiceString = getTargetServiceComponentNameString( - mContext, UserHandle.USER_CURRENT); - if (currentShortcutServiceString == null) { + final ComponentName targetComponentName = getShortcutTargetComponentName(); + if (targetComponentName == null) { return null; } - final ComponentName targetComponentName = - ComponentName.unflattenFromString(currentShortcutServiceString); final ToggleableFrameworkFeatureInfo frameworkFeatureInfo = getFrameworkShortcutFeaturesMap().get(targetComponentName); if (frameworkFeatureInfo != null) { @@ -372,6 +363,36 @@ public class AccessibilityShortcutController { } /** + * Returns {@code true} if any shortcut targets were assigned to accessibility shortcut key. + */ + private boolean hasShortcutTarget() { + // AccessibilityShortcutController is initialized earlier than AccessibilityManagerService. + // AccessibilityManager#getAccessibilityShortcutTargets may not return correct shortcut + // targets during boot. Needs to read settings directly here. + String shortcutTargets = Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, mUserId); + if (TextUtils.isEmpty(shortcutTargets)) { + shortcutTargets = mContext.getString(R.string.config_defaultAccessibilityService); + } + return !TextUtils.isEmpty(shortcutTargets); + } + + /** + * Gets the component name of the shortcut target. + * + * @return The component name, or null if it's assigned by multiple targets. + */ + private ComponentName getShortcutTargetComponentName() { + final List<String> shortcutTargets = mFrameworkObjectProvider + .getAccessibilityManagerInstance(mContext) + .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY); + if (shortcutTargets.size() != 1) { + return null; + } + return ComponentName.unflattenFromString(shortcutTargets.get(0)); + } + + /** * Class to wrap TextToSpeech for shortcut dialog spoken feedback. */ private class TtsPrompt implements TextToSpeech.OnInitListener { diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java new file mode 100644 index 000000000000..2fd5bfd71656 --- /dev/null +++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.app; +import android.annotation.IntDef; +import android.content.Context; +import android.os.UserHandle; +import android.view.View; +import android.view.ViewGroup; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.widget.PagerAdapter; + +import com.android.internal.util.Preconditions; +import com.android.internal.widget.ViewPager; + +/** + * Skeletal {@link PagerAdapter} implementation of a work or personal profile page for + * intent resolution (including share sheet). + */ +public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { + + static final int PROFILE_PERSONAL = 0; + static final int PROFILE_WORK = 1; + @IntDef({PROFILE_PERSONAL, PROFILE_WORK}) + @interface Profile {} + + private final Context mContext; + private int mCurrentPage; + + AbstractMultiProfilePagerAdapter(Context context, int currentPage) { + mContext = Preconditions.checkNotNull(context); + mCurrentPage = currentPage; + } + + Context getContext() { + return mContext; + } + + /** + * Sets this instance of this class as {@link ViewPager}'s {@link PagerAdapter} and sets + * an {@link ViewPager.OnPageChangeListener} where it keeps track of the currently displayed + * page and rebuilds the list. + */ + void setupViewPager(ViewPager viewPager) { + viewPager.setCurrentItem(mCurrentPage); + viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected(int position) { + mCurrentPage = position; + getCurrentListAdapter().rebuildList(); + } + }); + viewPager.setAdapter(this); + } + + @Override + public ViewGroup instantiateItem(ViewGroup container, int position) { + final ProfileDescriptor profileDescriptor = getItem(position); + setupListAdapter(position); + container.addView(profileDescriptor.rootView); + return profileDescriptor.rootView; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object view) { + container.removeView((View) view); + } + + @Override + public int getCount() { + return getItemCount(); + } + + protected int getCurrentPage() { + return mCurrentPage; + } + + UserHandle getCurrentUserHandle() { + return getCurrentListAdapter().mResolverListController.getUserHandle(); + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + + @Override + public CharSequence getPageTitle(int position) { + return null; + } + + /** + * Returns the {@link ProfileDescriptor} relevant to the given <code>pageIndex</code>. + * <ul> + * <li>For a device with only one user, <code>pageIndex</code> value of + * <code>0</code> would return the personal profile {@link ProfileDescriptor}.</li> + * <li>For a device with a work profile, <code>pageIndex</code> value of <code>0</code> would + * return the personal profile {@link ProfileDescriptor}, and <code>pageIndex</code> value of + * <code>1</code> would return the work profile {@link ProfileDescriptor}.</li> + * </ul> + */ + abstract ProfileDescriptor getItem(int pageIndex); + + /** + * Returns the number of {@link ProfileDescriptor} objects. + * <p>For a normal consumer device with only one user returns <code>1</code>. + * <p>For a device with a work profile returns <code>2</code>. + */ + abstract int getItemCount(); + + /** + * Responsible for assigning an adapter to the list view for the relevant page, specified by + * <code>pageIndex</code>, and other list view-related initialization procedures. + */ + abstract void setupListAdapter(int pageIndex); + + /** + * Returns the adapter of the list view for the relevant page specified by + * <code>pageIndex</code>. + * <p>This method is meant to be implemented with an implementation-specific return type + * depending on the adapter type. + */ + abstract Object getAdapterForIndex(int pageIndex); + + @VisibleForTesting + public abstract ResolverListAdapter getCurrentListAdapter(); + + abstract Object getCurrentRootAdapter(); + + abstract ViewGroup getCurrentAdapterView(); + + protected class ProfileDescriptor { + final ViewGroup rootView; + ProfileDescriptor(ViewGroup rootView) { + this.rootView = rootView; + } + } +}
\ No newline at end of file diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 183e9a6faf09..1af39265dbcb 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -98,6 +98,7 @@ import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; +import android.view.WindowInsets; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.ImageView; @@ -173,7 +174,6 @@ public class ChooserActivity extends ResolverActivity implements @VisibleForTesting public static final int LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS = 250; - private static final int SINGLE_CELL_SPAN_SIZE = 1; private boolean mIsAppPredictorComponentAvailable; private AppPredictor mAppPredictor; @@ -229,9 +229,6 @@ public class ChooserActivity extends ResolverActivity implements private long mQueriedTargetServicesTimeMs; private long mQueriedSharingShortcutsTimeMs; - private RecyclerView mRecyclerView; - private ChooserListAdapter mChooserListAdapter; - private ChooserGridAdapter mChooserGridAdapter; private int mChooserRowServiceSpacing; private int mCurrAvailableWidth = 0; @@ -265,6 +262,9 @@ public class ChooserActivity extends ResolverActivity implements private ContentPreviewCoordinator mPreviewCoord; + @VisibleForTesting + protected ChooserMultiProfilePagerAdapter mChooserMultiProfilePagerAdapter; + private class ContentPreviewCoordinator { private static final int IMAGE_FADE_IN_MILLIS = 150; private static final int IMAGE_LOAD_TIMEOUT = 1; @@ -362,8 +362,8 @@ public class ChooserActivity extends ResolverActivity implements Log.i(TAG, "Hiding image preview area. Timed out waiting for preview to load" + " within " + mImageLoadTimeoutMillis + "ms."); collapseParentView(); - if (mChooserGridAdapter != null) { - mChooserGridAdapter.hideContentPreview(); + if (mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() != null) { + mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().hideContentPreview(); } mHideParentOnFail = false; } @@ -431,13 +431,14 @@ public class ChooserActivity extends ResolverActivity implements logDirectShareTargetReceived( MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_CHOOSER_SERVICE); sendVoiceChoicesIfNeeded(); - mChooserListAdapter.completeServiceTargetLoading(); + mChooserMultiProfilePagerAdapter.getCurrentListAdapter() + .completeServiceTargetLoading(); } } @Override public void handleMessage(Message msg) { - if (mChooserListAdapter == null || isDestroyed()) { + if (mChooserMultiProfilePagerAdapter.getCurrentListAdapter() == null || isDestroyed()) { return; } @@ -452,8 +453,10 @@ public class ChooserActivity extends ResolverActivity implements break; } if (sri.resultTargets != null) { - mChooserListAdapter.addServiceResults(sri.originalTarget, - sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET); + // TODO(arangelov): Instead of using getCurrentListAdapter(), pass the + // profileId as part of the message. + mChooserMultiProfilePagerAdapter.getCurrentListAdapter().addServiceResults( + sri.originalTarget, sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET); } unbindService(sri.connection); sri.connection.destroy(); @@ -476,15 +479,15 @@ public class ChooserActivity extends ResolverActivity implements Log.d(TAG, "LIST_VIEW_UPDATE_MESSAGE; "); } - mChooserListAdapter.refreshListView(); + mChooserMultiProfilePagerAdapter.getCurrentListAdapter().refreshListView(); break; case SHORTCUT_MANAGER_SHARE_TARGET_RESULT: if (DEBUG) Log.d(TAG, "SHORTCUT_MANAGER_SHARE_TARGET_RESULT"); final ServiceResultInfo resultInfo = (ServiceResultInfo) msg.obj; if (resultInfo.resultTargets != null) { - mChooserListAdapter.addServiceResults(resultInfo.originalTarget, - resultInfo.resultTargets, msg.arg1); + mChooserMultiProfilePagerAdapter.getCurrentListAdapter().addServiceResults( + resultInfo.originalTarget, resultInfo.resultTargets, msg.arg1); } break; @@ -504,6 +507,7 @@ public class ChooserActivity extends ResolverActivity implements protected void onCreate(Bundle savedInstanceState) { final long intentReceivedTime = System.currentTimeMillis(); // This is the only place this value is being set. Effectively final. + //TODO(arangelov) - should there be a mIsAppPredictorComponentAvailable flag for work tab? mIsAppPredictorComponentAvailable = isAppPredictionServiceAvailable(); mIsSuccessfullySelected = false; @@ -638,19 +642,24 @@ public class ChooserActivity extends ResolverActivity implements if (appPredictor != null) { mDirectShareAppTargetCache = new HashMap<>(); mAppPredictorCallback = resultList -> { + //TODO(arangelov) Take care of edge case when callback called after swiping tabs if (isFinishing() || isDestroyed()) { return; } - if (mChooserListAdapter.getCount() == 0) { + if (mChooserMultiProfilePagerAdapter.getCurrentListAdapter().getCount() == 0) { return; } if (resultList.isEmpty()) { // APS may be disabled, so try querying targets ourselves. - queryDirectShareTargets(mChooserListAdapter, true); + //TODO(arangelov) queryDirectShareTargets indirectly uses mIntents. + // Investigate implications for work tab. + queryDirectShareTargets( + mChooserMultiProfilePagerAdapter.getCurrentListAdapter(), true); return; } final List<DisplayResolveInfo> driList = - getDisplayResolveInfos(mChooserListAdapter); + getDisplayResolveInfos( + mChooserMultiProfilePagerAdapter.getCurrentListAdapter()); final List<ShortcutManager.ShareShortcutInfo> shareShortcutInfos = new ArrayList<>(); for (AppTarget appTarget : resultList) { @@ -684,21 +693,22 @@ public class ChooserActivity extends ResolverActivity implements final float chooserHeaderScrollElevation = getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation); - mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - public void onScrollStateChanged(RecyclerView view, int scrollState) { - } - - public void onScrolled(RecyclerView view, int dx, int dy) { - if (view.getChildCount() > 0) { - View child = view.getLayoutManager().findViewByPosition(0); - if (child == null || child.getTop() < 0) { - chooserHeader.setElevation(chooserHeaderScrollElevation); - return; + mChooserMultiProfilePagerAdapter.getCurrentAdapterView().addOnScrollListener( + new RecyclerView.OnScrollListener() { + public void onScrollStateChanged(RecyclerView view, int scrollState) { } - } - chooserHeader.setElevation(defaultElevation); - } + public void onScrolled(RecyclerView view, int dx, int dy) { + if (view.getChildCount() > 0) { + View child = view.getLayoutManager().findViewByPosition(0); + if (child == null || child.getTop() < 0) { + chooserHeader.setElevation(chooserHeaderScrollElevation); + return; + } + } + + chooserHeader.setElevation(defaultElevation); + } }); mResolverDrawerLayout.setOnCollapsedChangedListener( @@ -738,6 +748,71 @@ public class ChooserActivity extends ResolverActivity implements return context.getSharedPreferences(prefsFile, MODE_PRIVATE); } + @Override + protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter( + Intent[] initialIntents, + List<ResolveInfo> rList, + boolean filterLastUsed) { + if (hasWorkProfile() && ENABLE_TABBED_VIEW) { + mChooserMultiProfilePagerAdapter = createChooserMultiProfilePagerAdapterForTwoProfiles( + initialIntents, rList, filterLastUsed); + } else { + mChooserMultiProfilePagerAdapter = createChooserMultiProfilePagerAdapterForOneProfile( + initialIntents, rList, filterLastUsed); + } + return mChooserMultiProfilePagerAdapter; + } + + private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForOneProfile( + Intent[] initialIntents, + List<ResolveInfo> rList, + boolean filterLastUsed) { + ChooserGridAdapter adapter = createChooserGridAdapter( + /* context */ this, + /* payloadIntents */ mIntents, + initialIntents, + rList, + filterLastUsed, + mUseLayoutForBrowsables, + /* userHandle */ UserHandle.of(UserHandle.myUserId())); + return new ChooserMultiProfilePagerAdapter( + /* context */ this, + adapter); + } + + private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForTwoProfiles( + Intent[] initialIntents, + List<ResolveInfo> rList, + boolean filterLastUsed) { + ChooserGridAdapter personalAdapter = createChooserGridAdapter( + /* context */ this, + /* payloadIntents */ mIntents, + initialIntents, + rList, + filterLastUsed, + mUseLayoutForBrowsables, + /* userHandle */ getPersonalProfileUserHandle()); + ChooserGridAdapter workAdapter = createChooserGridAdapter( + /* context */ this, + /* payloadIntents */ mIntents, + initialIntents, + rList, + filterLastUsed, + mUseLayoutForBrowsables, + /* userHandle */ getWorkProfileUserHandle()); + return new ChooserMultiProfilePagerAdapter( + /* context */ this, + personalAdapter, + workAdapter, + /* defaultProfile */ getCurrentProfile()); + } + + @Override + protected boolean postRebuildList(boolean rebuildCompleted) { + mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().maybeLogActionShareWithPreview(); + return postRebuildListInternal(rebuildCompleted); + } + /** * Returns true if app prediction service is defined and the component exists on device. */ @@ -776,7 +851,7 @@ public class ChooserActivity extends ResolverActivity implements * set up) */ protected boolean isWorkProfile() { - return ((UserManager) getSystemService(Context.USER_SERVICE)) + return getSystemService(UserManager.class) .getUserInfo(UserHandle.myUserId()).isManagedProfile(); } @@ -785,7 +860,9 @@ public class ChooserActivity extends ResolverActivity implements return new PackageMonitor() { @Override public void onSomePackagesChanged() { - mAdapter.handlePackagesChanged(); + // TODO(arangelov): Dispatch this to all adapters when we have the helper methods + // in a follow-up CL + mChooserMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged(); updateProfileViewButton(); } }; @@ -1239,36 +1316,14 @@ public class ChooserActivity extends ResolverActivity implements } @Override - public void onPrepareAdapterView(ResolverListAdapter adapter, boolean isVisible) { - mRecyclerView = findViewById(R.id.resolver_list); - if (!isVisible) { - mRecyclerView.setVisibility(View.GONE); - return; - } - mRecyclerView.setVisibility(View.VISIBLE); + public void onPrepareAdapterView(ResolverListAdapter adapter) { + mChooserMultiProfilePagerAdapter.getCurrentAdapterView().setVisibility(View.VISIBLE); if (mCallerChooserTargets != null && mCallerChooserTargets.length > 0) { - mChooserListAdapter.addServiceResults(null, Lists.newArrayList(mCallerChooserTargets), + mChooserMultiProfilePagerAdapter.getCurrentListAdapter().addServiceResults( + /* origTarget */ null, + Lists.newArrayList(mCallerChooserTargets), TARGET_TYPE_DEFAULT); } - mChooserGridAdapter = new ChooserGridAdapter(mChooserListAdapter); - GridLayoutManager glm = (GridLayoutManager) mRecyclerView.getLayoutManager(); - glm.setSpanCount(mChooserGridAdapter.getMaxTargetsPerRow()); - glm.setSpanSizeLookup( - new GridLayoutManager.SpanSizeLookup() { - @Override - public int getSpanSize(int position) { - return mChooserGridAdapter.getItemViewType(position) - == ChooserGridAdapter.VIEW_TYPE_NORMAL - ? SINGLE_CELL_SPAN_SIZE - : glm.getSpanCount(); - } - }); - } - - @Override - protected boolean postRebuildList(boolean rebuildCompleted) { - mChooserListAdapter = (ChooserListAdapter) mAdapter; - return postRebuildListInternal(rebuildCompleted); } @Override @@ -1348,7 +1403,10 @@ public class ChooserActivity extends ResolverActivity implements @Override public void startSelected(int which, boolean always, boolean filtered) { - TargetInfo targetInfo = mChooserListAdapter.targetInfoForPosition(which, filtered); + ChooserListAdapter currentListAdapter = + mChooserMultiProfilePagerAdapter.getCurrentListAdapter(); + TargetInfo targetInfo = currentListAdapter + .targetInfoForPosition(which, filtered); if (targetInfo != null && targetInfo instanceof NotSelectableTargetInfo) { return; } @@ -1356,7 +1414,7 @@ public class ChooserActivity extends ResolverActivity implements final long selectionCost = System.currentTimeMillis() - mChooserShownTime; super.startSelected(which, always, filtered); - if (mChooserListAdapter.getCount() > 0) { + if (currentListAdapter.getCount() > 0) { // Log the index of which type of target the user picked. // Lower values mean the ranking was better. int cat = 0; @@ -1364,13 +1422,12 @@ public class ChooserActivity extends ResolverActivity implements int directTargetAlsoRanked = -1; int numCallerProvided = 0; HashedStringCache.HashResult directTargetHashed = null; - switch (mChooserListAdapter.getPositionTargetType(which)) { + switch (currentListAdapter.getPositionTargetType(which)) { case ChooserListAdapter.TARGET_SERVICE: cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET; // Log the package name + target name to answer the question if most users // share to mostly the same person or to a bunch of different people. - ChooserTarget target = - mChooserListAdapter.getChooserTargetForValue(value); + ChooserTarget target = currentListAdapter.getChooserTargetForValue(value); directTargetHashed = HashedStringCache.getInstance().hashString( this, TAG, @@ -1386,8 +1443,8 @@ public class ChooserActivity extends ResolverActivity implements case ChooserListAdapter.TARGET_CALLER: case ChooserListAdapter.TARGET_STANDARD: cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET; - value -= mChooserListAdapter.getSelectableServiceTargetCount(); - numCallerProvided = mChooserListAdapter.getCallerTargetCount(); + value -= currentListAdapter.getSelectableServiceTargetCount(); + numCallerProvided = currentListAdapter.getCallerTargetCount(); break; case ChooserListAdapter.TARGET_STANDARD_AZ: // A-Z targets are unranked standard targets; we use -1 to mark that they @@ -1429,11 +1486,13 @@ public class ChooserActivity extends ResolverActivity implements private int getRankedPosition(SelectableTargetInfo targetInfo) { String targetPackageName = targetInfo.getChooserTarget().getComponentName().getPackageName(); - int maxRankedResults = Math.min(mChooserListAdapter.mDisplayList.size(), - MAX_LOG_RANK_POSITION); + ChooserListAdapter currentListAdapter = + mChooserMultiProfilePagerAdapter.getCurrentListAdapter(); + int maxRankedResults = Math.min(currentListAdapter.mDisplayList.size(), + MAX_LOG_RANK_POSITION); for (int i = 0; i < maxRankedResults; i++) { - if (mChooserListAdapter.mDisplayList.get(i) + if (currentListAdapter.mDisplayList.get(i) .getResolveInfo().activityInfo.packageName.equals(targetPackageName)) { return i; } @@ -1577,6 +1636,7 @@ public class ChooserActivity extends ResolverActivity implements } } // Default to just querying ShortcutManager if AppPredictor not present. + //TODO(arangelov) we're using mIntents here, investicate possible implications on work tab final IntentFilter filter = getTargetIntentFilter(); if (filter == null) { return; @@ -1584,6 +1644,7 @@ public class ChooserActivity extends ResolverActivity implements final List<DisplayResolveInfo> driList = getDisplayResolveInfos(adapter); AsyncTask.execute(() -> { + //TODO(arangelov) use the selected probile tab's ShortcutManager ShortcutManager sm = (ShortcutManager) getSystemService(Context.SHORTCUT_SERVICE); List<ShortcutManager.ShareShortcutInfo> resultList = sm.getShareTargets(filter); sendShareShortcutInfoList(resultList, driList, null); @@ -1779,9 +1840,11 @@ public class ChooserActivity extends ResolverActivity implements final ResolveInfo ri = info.getResolveInfo(); Intent targetIntent = getTargetIntent(); if (ri != null && ri.activityInfo != null && targetIntent != null) { - if (mAdapter != null) { - mAdapter.updateModel(info.getResolvedComponentName()); - mAdapter.updateChooserCounts(ri.activityInfo.packageName, getUserId(), + ChooserListAdapter currentListAdapter = + mChooserMultiProfilePagerAdapter.getCurrentListAdapter(); + if (currentListAdapter != null) { + currentListAdapter.updateModel(info.getResolvedComponentName()); + currentListAdapter.updateChooserCounts(ri.activityInfo.packageName, getUserId(), targetIntent.getAction()); } if (DEBUG) { @@ -1956,8 +2019,9 @@ public class ChooserActivity extends ResolverActivity implements Intent targetIntent, String referrerPackageName, int launchedFromUid, + UserHandle userId, AbstractResolverComparator resolverComparator) { - super(context, pm, targetIntent, referrerPackageName, launchedFromUid, + super(context, pm, targetIntent, referrerPackageName, launchedFromUid, userId, resolverComparator); } @@ -1980,17 +2044,18 @@ public class ChooserActivity extends ResolverActivity implements } } - @Override - public ResolverListAdapter createAdapter(Context context, List<Intent> payloadIntents, - Intent[] initialIntents, List<ResolveInfo> rList, - boolean filterLastUsed, boolean useLayoutForBrowsables) { - return new ChooserListAdapter(context, payloadIntents, - initialIntents, rList, filterLastUsed, createListController(), - useLayoutForBrowsables, this, this); + @VisibleForTesting + public ChooserGridAdapter createChooserGridAdapter(Context context, + List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, + boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) { + return new ChooserGridAdapter( + new ChooserListAdapter(context, payloadIntents, initialIntents, rList, + filterLastUsed, createListController(userHandle), useLayoutForBrowsables, + this, this)); } @VisibleForTesting - protected ResolverListController createListController() { + protected ResolverListController createListController(UserHandle userHandle) { AppPredictor appPredictor = getAppPredictorForShareActivitesIfEnabled(); AbstractResolverComparator resolverComparator; if (appPredictor != null) { @@ -2008,6 +2073,7 @@ public class ChooserActivity extends ResolverActivity implements getTargetIntent(), getReferrerPackageName(), mLaunchedFromUid, + userHandle, resolverComparator); } @@ -2041,8 +2107,8 @@ public class ChooserActivity extends ResolverActivity implements } private void handleScroll(View view, int x, int y, int oldx, int oldy) { - if (mChooserGridAdapter != null) { - mChooserGridAdapter.handleScroll(view, y, oldy); + if (mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() != null) { + mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().handleScroll(view, y, oldy); } } @@ -2053,37 +2119,42 @@ public class ChooserActivity extends ResolverActivity implements */ private void handleLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - if (mChooserGridAdapter == null || mRecyclerView == null) { + if (mChooserMultiProfilePagerAdapter == null) { + return; + } + RecyclerView recyclerView = mChooserMultiProfilePagerAdapter.getCurrentAdapterView(); + ChooserGridAdapter gridAdapter = mChooserMultiProfilePagerAdapter.getCurrentRootAdapter(); + if (gridAdapter == null || recyclerView == null) { return; } final int availableWidth = right - left - v.getPaddingLeft() - v.getPaddingRight(); - if (mChooserGridAdapter.consumeLayoutRequest() - || mChooserGridAdapter.calculateChooserTargetWidth(availableWidth) - || mRecyclerView.getAdapter() == null + if (gridAdapter.consumeLayoutRequest() + || gridAdapter.calculateChooserTargetWidth(availableWidth) + || recyclerView.getAdapter() == null || availableWidth != mCurrAvailableWidth) { mCurrAvailableWidth = availableWidth; - mRecyclerView.setAdapter(mChooserGridAdapter); - ((GridLayoutManager) mRecyclerView.getLayoutManager()) - .setSpanCount(mChooserGridAdapter.getMaxTargetsPerRow()); + recyclerView.setAdapter(gridAdapter); + ((GridLayoutManager) recyclerView.getLayoutManager()) + .setSpanCount(gridAdapter.getMaxTargetsPerRow()); getMainThreadHandler().post(() -> { - if (mResolverDrawerLayout == null || mChooserGridAdapter == null) { + if (mResolverDrawerLayout == null || gridAdapter == null) { return; } final int bottomInset = mSystemWindowInsets != null ? mSystemWindowInsets.bottom : 0; int offset = bottomInset; - int rowsToShow = mChooserGridAdapter.getContentPreviewRowCount() - + mChooserGridAdapter.getProfileRowCount() - + mChooserGridAdapter.getServiceTargetRowCount() - + mChooserGridAdapter.getCallerAndRankedTargetRowCount(); + int rowsToShow = gridAdapter.getContentPreviewRowCount() + + gridAdapter.getProfileRowCount() + + gridAdapter.getServiceTargetRowCount() + + gridAdapter.getCallerAndRankedTargetRowCount(); // then this is most likely not a SEND_* action, so check // the app target count if (rowsToShow == 0) { - rowsToShow = mChooserGridAdapter.getRowCount(); + rowsToShow = gridAdapter.getRowCount(); } // still zero? then use a default height and leave, which @@ -2097,9 +2168,9 @@ public class ChooserActivity extends ResolverActivity implements int directShareHeight = 0; rowsToShow = Math.min(4, rowsToShow); - for (int i = 0, childCount = mRecyclerView.getChildCount(); + for (int i = 0, childCount = recyclerView.getChildCount(); i < childCount && rowsToShow > 0; i++) { - View child = mRecyclerView.getChildAt(i); + View child = recyclerView.getChildAt(i); if (((GridLayoutManager.LayoutParams) child.getLayoutParams()).getSpanIndex() != 0) { continue; @@ -2107,9 +2178,9 @@ public class ChooserActivity extends ResolverActivity implements int height = child.getHeight(); offset += height; - if (mChooserGridAdapter.getTargetType( - mRecyclerView.getChildAdapterPosition(child)) - == mChooserListAdapter.TARGET_SERVICE) { + if (gridAdapter.getTargetType( + recyclerView.getChildAdapterPosition(child)) + == ChooserListAdapter.TARGET_SERVICE) { directShareHeight = height; } rowsToShow--; @@ -2145,13 +2216,13 @@ public class ChooserActivity extends ResolverActivity implements @Override // ResolverListCommunicator public void onHandlePackagesChanged() { mServicesRequested.clear(); - mAdapter.notifyDataSetChanged(); + mChooserMultiProfilePagerAdapter.getCurrentListAdapter().notifyDataSetChanged(); super.onHandlePackagesChanged(); } @Override // SelectableTargetInfoCommunicator public ActivityInfoPresentationGetter makePresentationGetter(ActivityInfo info) { - return mChooserListAdapter.makePresentationGetter(info); + return mChooserMultiProfilePagerAdapter.getCurrentListAdapter().makePresentationGetter(info); } @Override // SelectableTargetInfoCommunicator @@ -2161,9 +2232,9 @@ public class ChooserActivity extends ResolverActivity implements @Override // ChooserListCommunicator public int getMaxRankedTargets() { - return mChooserGridAdapter == null + return mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() == null ? ChooserGridAdapter.MAX_TARGETS_PER_ROW_PORTRAIT - : mChooserGridAdapter.getMaxTargetsPerRow(); + : mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().getMaxTargetsPerRow(); } @Override // ChooserListCommunicator @@ -2174,19 +2245,21 @@ public class ChooserActivity extends ResolverActivity implements @Override public void onListRebuilt() { - if (mChooserListAdapter.mDisplayList == null - || mChooserListAdapter.mDisplayList.isEmpty()) { - mChooserListAdapter.notifyDataSetChanged(); + final ChooserListAdapter currentListAdapter = + mChooserMultiProfilePagerAdapter.getCurrentListAdapter(); + if (currentListAdapter.mDisplayList == null + || currentListAdapter.mDisplayList.isEmpty()) { + currentListAdapter.notifyDataSetChanged(); } else { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... voids) { - mChooserListAdapter.updateAlphabeticalList(); + currentListAdapter.updateAlphabeticalList(); return null; } @Override protected void onPostExecute(Void aVoid) { - mChooserListAdapter.notifyDataSetChanged(); + currentListAdapter.notifyDataSetChanged(); } }.execute(); } @@ -2202,14 +2275,14 @@ public class ChooserActivity extends ResolverActivity implements Log.d(TAG, "querying direct share targets from ShortcutManager"); } - queryDirectShareTargets(mChooserListAdapter, false); + queryDirectShareTargets(currentListAdapter, false); } if (USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS) { if (DEBUG) { Log.d(TAG, "List built querying services"); } - queryTargetServices(mChooserListAdapter); + queryTargetServices(currentListAdapter); } } @@ -2250,8 +2323,8 @@ public class ChooserActivity extends ResolverActivity implements false/* always */, true/* filterd */)); itemView.setOnLongClickListener(v -> { showTargetDetails( - mChooserListAdapter.resolveInfoForPosition( - mListPosition, true/* filtered */)); + mChooserMultiProfilePagerAdapter.getCurrentListAdapter() + .resolveInfoForPosition(mListPosition, /* filtered */ true)); return true; }); } @@ -2259,6 +2332,29 @@ public class ChooserActivity extends ResolverActivity implements } /** + * Intentionally override the {@link ResolverActivity} implementation as we only need that + * implementation for the intent resolver case. + */ + @Override + protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { + return insets.consumeSystemWindowInsets(); + } + + /** + * Intentionally override the {@link ResolverActivity} implementation as we only need that + * implementation for the intent resolver case. + */ + @Override + public void onButtonClick(View v) {} + + /** + * Intentionally override the {@link ResolverActivity} implementation as we only need that + * implementation for the intent resolver case. + */ + @Override + protected void resetButtonBar() {} + + /** * Adapter for all types of items and targets in ShareSheet. * Note that ranked sections like Direct Share - while appearing grid-like - are handled on the * row level by this adapter but not on the item level. Individual targets within the row are @@ -2329,12 +2425,11 @@ public class ChooserActivity extends ResolverActivity implements return false; } - private int getMaxTargetsPerRow() { + int getMaxTargetsPerRow() { int maxTargets = MAX_TARGETS_PER_ROW_PORTRAIT; if (shouldDisplayLandscape(getResources().getConfiguration().orientation)) { maxTargets = MAX_TARGETS_PER_ROW_LANDSCAPE; } - return maxTargets; } @@ -2477,10 +2572,6 @@ public class ChooserActivity extends ResolverActivity implements private ViewGroup createContentPreviewView(ViewGroup parent) { Intent targetIntent = getTargetIntent(); int previewType = findPreferredContentPreview(targetIntent, getContentResolver()); - - getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW) - .setSubtype(previewType)); - return displayContentPreview(previewType, targetIntent, mLayoutInflater, parent); } @@ -2667,6 +2758,7 @@ public class ChooserActivity extends ResolverActivity implements for (int i = 0; i < columnCount; i++) { final View v = holder.getView(i); + if (start + i <= end) { holder.setViewVisibility(i, View.VISIBLE); holder.setItemIndex(i, start + i); @@ -2712,9 +2804,29 @@ public class ChooserActivity extends ResolverActivity implements && !isInMultiWindowMode(); if (mDirectShareViewHolder != null && canExpandDirectShare) { - mDirectShareViewHolder.handleScroll(mRecyclerView, y, oldy, getMaxTargetsPerRow()); + mDirectShareViewHolder.handleScroll( + mChooserMultiProfilePagerAdapter.getCurrentAdapterView(), y, oldy, + getMaxTargetsPerRow()); } } + + public ChooserListAdapter getListAdapter() { + return mChooserListAdapter; + } + + void maybeLogActionShareWithPreview() { + if (getContentPreviewRowCount() == 0) { + return; + } + Intent targetIntent = getTargetIntent(); + int previewType = findPreferredContentPreview(targetIntent, getContentResolver()); + getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW) + .setSubtype(previewType)); + } + + boolean shouldCellSpan(int position) { + return getItemViewType(position) == VIEW_TYPE_NORMAL; + } } /** @@ -2898,7 +3010,8 @@ public class ChooserActivity extends ResolverActivity implements // only expand if we have more than maxTargetsPerRow, and delay that decision // until they start to scroll - if (mChooserListAdapter.getSelectableServiceTargetCount() <= maxTargetsPerRow) { + if (mChooserMultiProfilePagerAdapter.getCurrentListAdapter() + .getSelectableServiceTargetCount() <= maxTargetsPerRow) { mHideDirectShareExpansion = true; return; } diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java new file mode 100644 index 000000000000..aa8ab2865d92 --- /dev/null +++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.app; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.widget.GridLayoutManager; +import com.android.internal.widget.PagerAdapter; +import com.android.internal.widget.RecyclerView; + +/** + * A {@link PagerAdapter} which describes the work and personal profile share sheet screens. + */ +@VisibleForTesting +public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAdapter { + private static final int SINGLE_CELL_SPAN_SIZE = 1; + + private final ChooserProfileDescriptor[] mItems; + + ChooserMultiProfilePagerAdapter(Context context, + ChooserActivity.ChooserGridAdapter adapter) { + super(context, /* currentPage */ 0); + mItems = new ChooserProfileDescriptor[] { + createProfileDescriptor(adapter) + }; + } + + ChooserMultiProfilePagerAdapter(Context context, + ChooserActivity.ChooserGridAdapter personalAdapter, + ChooserActivity.ChooserGridAdapter workAdapter, + @Profile int defaultProfile) { + super(context, /* currentPage */ defaultProfile); + mItems = new ChooserProfileDescriptor[] { + createProfileDescriptor(personalAdapter), + createProfileDescriptor(workAdapter) + }; + } + + private ChooserProfileDescriptor createProfileDescriptor( + ChooserActivity.ChooserGridAdapter adapter) { + final LayoutInflater inflater = LayoutInflater.from(getContext()); + final ViewGroup rootView = + (ViewGroup) inflater.inflate(R.layout.chooser_list_per_profile, null, false); + return new ChooserProfileDescriptor(rootView, adapter); + } + + RecyclerView getListViewForIndex(int index) { + return getItem(index).recyclerView; + } + + @Override + ChooserProfileDescriptor getItem(int pageIndex) { + return mItems[pageIndex]; + } + + @Override + int getItemCount() { + return mItems.length; + } + + @Override + ChooserActivity.ChooserGridAdapter getAdapterForIndex(int pageIndex) { + return mItems[pageIndex].chooserGridAdapter; + } + + @Override + void setupListAdapter(int pageIndex) { + final RecyclerView recyclerView = getItem(pageIndex).recyclerView; + ChooserActivity.ChooserGridAdapter chooserGridAdapter = + getItem(pageIndex).chooserGridAdapter; + recyclerView.setAdapter(chooserGridAdapter); + GridLayoutManager glm = (GridLayoutManager) recyclerView.getLayoutManager(); + glm.setSpanCount(chooserGridAdapter.getMaxTargetsPerRow()); + glm.setSpanSizeLookup( + new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + return chooserGridAdapter.shouldCellSpan(position) + ? SINGLE_CELL_SPAN_SIZE + : glm.getSpanCount(); + } + }); + } + + @Override + @VisibleForTesting + public ChooserListAdapter getCurrentListAdapter() { + return getAdapterForIndex(getCurrentPage()).getListAdapter(); + } + + @Override + ChooserActivity.ChooserGridAdapter getCurrentRootAdapter() { + return getAdapterForIndex(getCurrentPage()); + } + + @Override + RecyclerView getCurrentAdapterView() { + return getListViewForIndex(getCurrentPage()); + } + + class ChooserProfileDescriptor extends ProfileDescriptor { + private ChooserActivity.ChooserGridAdapter chooserGridAdapter; + private RecyclerView recyclerView; + ChooserProfileDescriptor(ViewGroup rootView, ChooserActivity.ChooserGridAdapter adapter) { + super(rootView); + chooserGridAdapter = adapter; + recyclerView = rootView.findViewById(R.id.resolver_list); + } + } +} diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 9e38f3847f65..9cf5e9f47e7f 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -18,11 +18,15 @@ package com.android.internal.app; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static com.android.internal.app.AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL; +import static com.android.internal.app.AbstractMultiProfilePagerAdapter.PROFILE_WORK; + import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.UiThread; import android.annotation.UnsupportedAppUsage; import android.app.Activity; +import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.ActivityThread; import android.app.VoiceInteractor.PickOptionRequest; @@ -32,6 +36,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.PermissionChecker; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -71,6 +76,7 @@ import android.widget.Toast; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.app.AbstractMultiProfilePagerAdapter.Profile; import com.android.internal.app.chooser.DisplayResolveInfo; import com.android.internal.app.chooser.TargetInfo; import com.android.internal.content.PackageMonitor; @@ -98,10 +104,7 @@ public class ResolverActivity extends Activity implements public ResolverActivity() { } - @UnsupportedAppUsage - protected ResolverListAdapter mAdapter; private boolean mSafeForwardingMode; - private AbsListView mAdapterView; private Button mAlwaysButton; private Button mOnceButton; protected View mProfileView; @@ -142,8 +145,16 @@ public class ResolverActivity extends Activity implements private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key"; private static final String OPEN_LINKS_COMPONENT_KEY = "app_link_state"; + /** + * TODO(arangelov): Remove a couple of weeks after work/personal tabs are finalized. + */ + static final boolean ENABLE_TABBED_VIEW = false; + private final PackageMonitor mPackageMonitor = createPackageMonitor(); + @VisibleForTesting + protected AbstractMultiProfilePagerAdapter mMultiProfilePagerAdapter; + // Intent extra for connected audio devices public static final String EXTRA_IS_AUDIO_CAPTURE_DEVICE = "is_audio_capture_device"; @@ -229,7 +240,7 @@ public class ResolverActivity extends Activity implements return new PackageMonitor() { @Override public void onSomePackagesChanged() { - mAdapter.handlePackagesChanged(); + mMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged(); updateProfileViewButton(); } @@ -324,15 +335,13 @@ public class ResolverActivity extends Activity implements mSupportsAlwaysUseOption = supportsAlwaysUseOption; - // The last argument of createAdapter is whether to do special handling + // The last argument of createResolverListAdapter is whether to do special handling // of the last used choice to highlight it in the list. We need to always // turn this off when running under voice interaction, since it results in // a more complicated UI that the current voice interaction flow is not able // to handle. boolean filterLastUsed = mSupportsAlwaysUseOption && !isVoiceInteraction(); - mAdapter = createAdapter(this, mIntents, initialIntents, rList, - filterLastUsed, mUseLayoutForBrowsables); - + mMultiProfilePagerAdapter = createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed); if (configureContentView()) { return; } @@ -363,15 +372,96 @@ public class ResolverActivity extends Activity implements } final Set<String> categories = intent.getCategories(); - MetricsLogger.action(this, mAdapter.hasFilteredItem() + MetricsLogger.action(this, mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem() ? MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_APP_FEATURED : MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_NONE_FEATURED, intent.getAction() + ":" + intent.getType() + ":" + (categories != null ? Arrays.toString(categories.toArray()) : "")); } + protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter( + Intent[] initialIntents, + List<ResolveInfo> rList, + boolean filterLastUsed) { + AbstractMultiProfilePagerAdapter resolverMultiProfilePagerAdapter = null; + if (hasWorkProfile() && ENABLE_TABBED_VIEW) { + resolverMultiProfilePagerAdapter = + createResolverMultiProfilePagerAdapterForTwoProfiles( + initialIntents, rList, filterLastUsed); + } else { + resolverMultiProfilePagerAdapter = createResolverMultiProfilePagerAdapterForOneProfile( + initialIntents, rList, filterLastUsed); + } + return resolverMultiProfilePagerAdapter; + } + + private ResolverMultiProfilePagerAdapter createResolverMultiProfilePagerAdapterForOneProfile( + Intent[] initialIntents, + List<ResolveInfo> rList, boolean filterLastUsed) { + ResolverListAdapter adapter = createResolverListAdapter( + /* context */ this, + /* payloadIntents */ mIntents, + initialIntents, + rList, + filterLastUsed, + mUseLayoutForBrowsables, + /* userHandle */ UserHandle.of(UserHandle.myUserId())); + return new ResolverMultiProfilePagerAdapter( + /* context */ this, + adapter); + } + + private ResolverMultiProfilePagerAdapter createResolverMultiProfilePagerAdapterForTwoProfiles( + Intent[] initialIntents, + List<ResolveInfo> rList, + boolean filterLastUsed) { + ResolverListAdapter personalAdapter = createResolverListAdapter( + /* context */ this, + /* payloadIntents */ mIntents, + initialIntents, + rList, + filterLastUsed, + mUseLayoutForBrowsables, + /* userHandle */ getPersonalProfileUserHandle()); + ResolverListAdapter workAdapter = createResolverListAdapter( + /* context */ this, + /* payloadIntents */ mIntents, + initialIntents, + rList, + filterLastUsed, + mUseLayoutForBrowsables, + /* userHandle */ getWorkProfileUserHandle()); + return new ResolverMultiProfilePagerAdapter( + /* context */ this, + personalAdapter, + workAdapter, + /* defaultProfile */ getCurrentProfile()); + } + + protected @Profile int getCurrentProfile() { + return (UserHandle.myUserId() == UserHandle.USER_SYSTEM ? PROFILE_PERSONAL : PROFILE_WORK); + } + + protected UserHandle getPersonalProfileUserHandle() { + return UserHandle.of(ActivityManager.getCurrentUser()); + } + protected @Nullable UserHandle getWorkProfileUserHandle() { + UserManager userManager = getSystemService(UserManager.class); + for (final UserInfo userInfo : userManager.getProfiles(ActivityManager.getCurrentUser())) { + if (userInfo.isManagedProfile()) { + return userInfo.getUserHandle(); + } + } + return null; + } + + protected boolean hasWorkProfile() { + return getWorkProfileUserHandle() != null; + } + protected void onProfileClick(View v) { - final DisplayResolveInfo dri = mAdapter.getOtherProfile(); + final DisplayResolveInfo dri = + mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile(); if (dri == null) { return; } @@ -394,11 +484,13 @@ public class ResolverActivity extends Activity implements if (mFooterSpacer == null) { mFooterSpacer = new Space(getApplicationContext()); } else { - ((ListView) mAdapterView).removeFooterView(mFooterSpacer); + ((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter) + .getCurrentAdapterView().removeFooterView(mFooterSpacer); } mFooterSpacer.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, mSystemWindowInsets.bottom)); - ((ListView) mAdapterView).addFooterView(mFooterSpacer); + ((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter) + .getCurrentAdapterView().addFooterView(mFooterSpacer); } else { View emptyView = findViewById(R.id.empty); if (emptyView != null) { @@ -416,7 +508,7 @@ public class ResolverActivity extends Activity implements @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - mAdapter.handlePackagesChanged(); + mMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged(); if (mSystemWindowInsets != null) { mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, @@ -431,9 +523,10 @@ public class ResolverActivity extends Activity implements return; } - final Option[] options = new Option[mAdapter.getCount()]; + int count = mMultiProfilePagerAdapter.getCurrentListAdapter().getCount(); + final Option[] options = new Option[count]; for (int i = 0, N = options.length; i < N; i++) { - TargetInfo target = mAdapter.getItem(i); + TargetInfo target = mMultiProfilePagerAdapter.getCurrentListAdapter().getItem(i); if (target == null) { // If this occurs, a new set of targets is being loaded. Let that complete, // and have the next call to send voice choices proceed instead. @@ -482,8 +575,9 @@ public class ResolverActivity extends Activity implements return; } - final DisplayResolveInfo dri = mAdapter.getOtherProfile(); - if (dri != null) { + final DisplayResolveInfo dri = + mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile(); + if (dri != null && !ENABLE_TABBED_VIEW) { mProfileView.setVisibility(View.VISIBLE); View text = mProfileView.findViewById(R.id.profile_button); if (!(text instanceof TextView)) { @@ -534,7 +628,8 @@ public class ResolverActivity extends Activity implements // While there may already be a filtered item, we can only use it in the title if the list // is already sorted and all information relevant to it is already in the list. - final boolean named = mAdapter.getFilteredPosition() >= 0; + final boolean named = + mMultiProfilePagerAdapter.getCurrentListAdapter().getFilteredPosition() >= 0; if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) { return getString(defaultTitleRes); } else if (isHttpSchemeAndViewAction(intent)) { @@ -543,12 +638,14 @@ public class ResolverActivity extends Activity implements String dialogTitle = null; if (named && !mUseLayoutForBrowsables) { dialogTitle = getString(ActionTitle.BROWSABLE_APP_TITLE_RES, - mAdapter.getFilteredItem().getDisplayLabel()); + mMultiProfilePagerAdapter.getCurrentListAdapter().getFilteredItem() + .getDisplayLabel()); } else if (named && mUseLayoutForBrowsables) { dialogTitle = getString(ActionTitle.BROWSABLE_HOST_APP_TITLE_RES, intent.getData().getHost(), - mAdapter.getFilteredItem().getDisplayLabel()); - } else if (mAdapter.areAllTargetsBrowsers()) { + mMultiProfilePagerAdapter.getCurrentListAdapter().getFilteredItem() + .getDisplayLabel()); + } else if (mMultiProfilePagerAdapter.getCurrentListAdapter().areAllTargetsBrowsers()) { dialogTitle = getString(ActionTitle.BROWSABLE_TITLE_RES); } else { dialogTitle = getString(ActionTitle.BROWSABLE_HOST_TITLE_RES, @@ -557,7 +654,8 @@ public class ResolverActivity extends Activity implements return dialogTitle; } else { return named - ? getString(title.namedTitleRes, mAdapter.getFilteredItem().getDisplayLabel()) + ? getString(title.namedTitleRes, mMultiProfilePagerAdapter + .getCurrentListAdapter().getFilteredItem().getDisplayLabel()) : getString(title.titleRes); } } @@ -575,7 +673,7 @@ public class ResolverActivity extends Activity implements mPackageMonitor.register(this, getMainLooper(), false); mRegistered = true; } - mAdapter.handlePackagesChanged(); + mMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged(); updateProfileViewButton(); } @@ -608,8 +706,8 @@ public class ResolverActivity extends Activity implements if (!isChangingConfigurations() && mPickOptionRequest != null) { mPickOptionRequest.cancel(); } - if (mAdapter != null) { - mAdapter.onDestroy(); + if (mMultiProfilePagerAdapter.getCurrentListAdapter() != null) { + mMultiProfilePagerAdapter.getCurrentListAdapter().onDestroy(); } } @@ -657,8 +755,10 @@ public class ResolverActivity extends Activity implements private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos, boolean filtered) { boolean enabled = false; + ResolveInfo ri = null; if (hasValidSelection) { - ResolveInfo ri = mAdapter.resolveInfoForPosition(checkedPos, filtered); + ri = mMultiProfilePagerAdapter.getCurrentListAdapter() + .resolveInfoForPosition(checkedPos, filtered); if (ri == null) { Log.e(TAG, "Invalid position supplied to setAlwaysButtonEnabled"); return; @@ -676,16 +776,36 @@ public class ResolverActivity extends Activity implements .getString(R.string.activity_resolver_use_always)); } } + + ActivityInfo activityInfo = ri.activityInfo; + + boolean hasRecordPermission = + PermissionChecker.checkPermissionForPreflight( + getApplicationContext(), + android.Manifest.permission.RECORD_AUDIO, -1, + activityInfo.applicationInfo.uid, + activityInfo.packageName) + == android.content.pm.PackageManager.PERMISSION_GRANTED; + + if (!hasRecordPermission) { + // OK, we know the record permission, is this a capture device + boolean hasAudioCapture = + getIntent().getBooleanExtra( + ResolverActivity.EXTRA_IS_AUDIO_CAPTURE_DEVICE, false); + enabled = !hasAudioCapture; + } mAlwaysButton.setEnabled(enabled); } public void onButtonClick(View v) { final int id = v.getId(); - int which = mAdapter.hasFilteredItem() - ? mAdapter.getFilteredPosition() - : mAdapterView.getCheckedItemPosition(); - boolean hasIndexBeenFiltered = !mAdapter.hasFilteredItem(); - ResolveInfo ri = mAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered); + ListView listView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView(); + ResolverListAdapter currentListAdapter = mMultiProfilePagerAdapter.getCurrentListAdapter(); + int which = currentListAdapter.hasFilteredItem() + ? currentListAdapter.getFilteredPosition() + : listView.getCheckedItemPosition(); + boolean hasIndexBeenFiltered = !currentListAdapter.hasFilteredItem(); + ResolveInfo ri = currentListAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered); if (mUseLayoutForBrowsables && !ri.handleAllWebDataURI && id == R.id.button_always) { showSettingsForSelected(ri); @@ -716,7 +836,8 @@ public class ResolverActivity extends Activity implements if (isFinishing()) { return; } - ResolveInfo ri = mAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered); + ResolveInfo ri = mMultiProfilePagerAdapter.getCurrentListAdapter() + .resolveInfoForPosition(which, hasIndexBeenFiltered); if (mResolvingHome && hasManagedProfile() && !supportsManagedProfiles(ri)) { Toast.makeText(this, String.format(getResources().getString( com.android.internal.R.string.activity_resolver_work_profiles_support), @@ -725,7 +846,8 @@ public class ResolverActivity extends Activity implements return; } - TargetInfo target = mAdapter.targetInfoForPosition(which, hasIndexBeenFiltered); + TargetInfo target = mMultiProfilePagerAdapter.getCurrentListAdapter() + .targetInfoForPosition(which, hasIndexBeenFiltered); if (target == null) { return; } @@ -740,7 +862,8 @@ public class ResolverActivity extends Activity implements MetricsLogger.action( this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_TAP); } - MetricsLogger.action(this, mAdapter.hasFilteredItem() + MetricsLogger.action(this, + mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem() ? MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_APP_FEATURED : MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_NONE_FEATURED); finish(); @@ -763,10 +886,11 @@ public class ResolverActivity extends Activity implements } protected void onListRebuilt() { - int count = mAdapter.getUnfilteredCount(); - if (count == 1 && mAdapter.getOtherProfile() == null) { + int count = mMultiProfilePagerAdapter.getCurrentListAdapter().getUnfilteredCount(); + if (count == 1 && mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile() == null) { // Only one target, so we're a candidate to auto-launch! - final TargetInfo target = mAdapter.targetInfoForPosition(0, false); + final TargetInfo target = + mMultiProfilePagerAdapter.getCurrentListAdapter().targetInfoForPosition(0, false); if (shouldAutoLaunchSingleChoice(target)) { safelyStartActivity(target); finish(); @@ -778,8 +902,9 @@ public class ResolverActivity extends Activity implements final ResolveInfo ri = target.getResolveInfo(); final Intent intent = target != null ? target.getResolvedIntent() : null; - if (intent != null && (mSupportsAlwaysUseOption || mAdapter.hasFilteredItem()) - && mAdapter.mUnfilteredResolveList != null) { + if (intent != null && (mSupportsAlwaysUseOption + || mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem()) + && mMultiProfilePagerAdapter.getCurrentListAdapter().getUnfilteredResolveList() != null) { // Build a reasonable intent filter, based on what matched. IntentFilter filter = new IntentFilter(); Intent filterIntent; @@ -864,13 +989,14 @@ public class ResolverActivity extends Activity implements } if (filter != null) { - final int N = mAdapter.mUnfilteredResolveList.size(); + final int N = mMultiProfilePagerAdapter.getCurrentListAdapter() + .getUnfilteredResolveList().size(); ComponentName[] set; // If we don't add back in the component for forwarding the intent to a managed // profile, the preferred activity may not be updated correctly (as the set of // components we tell it we knew about will have changed). final boolean needToAddBackProfileForwardingComponent = - mAdapter.getOtherProfile() != null; + mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile() != null; if (!needToAddBackProfileForwardingComponent) { set = new ComponentName[N]; } else { @@ -879,15 +1005,18 @@ public class ResolverActivity extends Activity implements int bestMatch = 0; for (int i=0; i<N; i++) { - ResolveInfo r = mAdapter.mUnfilteredResolveList.get(i).getResolveInfoAt(0); + ResolveInfo r = mMultiProfilePagerAdapter.getCurrentListAdapter() + .getUnfilteredResolveList().get(i).getResolveInfoAt(0); set[i] = new ComponentName(r.activityInfo.packageName, r.activityInfo.name); if (r.match > bestMatch) bestMatch = r.match; } if (needToAddBackProfileForwardingComponent) { - set[N] = mAdapter.getOtherProfile().getResolvedComponentName(); - final int otherProfileMatch = mAdapter.getOtherProfile().getResolveInfo().match; + set[N] = mMultiProfilePagerAdapter.getCurrentListAdapter() + .getOtherProfile().getResolvedComponentName(); + final int otherProfileMatch = mMultiProfilePagerAdapter.getCurrentListAdapter() + .getOtherProfile().getResolveInfo().match; if (otherProfileMatch > bestMatch) bestMatch = otherProfileMatch; } @@ -926,7 +1055,8 @@ public class ResolverActivity extends Activity implements } } else { try { - mAdapter.mResolverListController.setLastChosen(intent, filter, bestMatch); + mMultiProfilePagerAdapter.getCurrentListAdapter() + .mResolverListController.setLastChosen(intent, filter, bestMatch); } catch (RemoteException re) { Log.d(TAG, "Error calling setLastChosenActivity\n" + re); } @@ -964,14 +1094,15 @@ public class ResolverActivity extends Activity implements if (mProfileSwitchMessageId != -1) { Toast.makeText(this, getString(mProfileSwitchMessageId), Toast.LENGTH_LONG).show(); } + UserHandle currentUserHandle = mMultiProfilePagerAdapter.getCurrentUserHandle(); if (!mSafeForwardingMode) { - if (cti.start(this, null)) { + if (cti.startAsUser(this, null, currentUserHandle)) { onActivityStarted(cti); } return; } try { - if (cti.startAsCaller(this, null, UserHandle.USER_NULL)) { + if (cti.startAsCaller(this, null, currentUserHandle.getIdentifier())) { onActivityStarted(cti); } } catch (RuntimeException e) { @@ -1041,27 +1172,27 @@ public class ResolverActivity extends Activity implements startActivity(in); } - public ResolverListAdapter createAdapter(Context context, List<Intent> payloadIntents, - Intent[] initialIntents, List<ResolveInfo> rList, - boolean filterLastUsed, boolean useLayoutForBrowsables) { - + @VisibleForTesting + protected ResolverListAdapter createResolverListAdapter(Context context, + List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, + boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) { Intent startIntent = getIntent(); boolean isAudioCaptureDevice = startIntent.getBooleanExtra(EXTRA_IS_AUDIO_CAPTURE_DEVICE, false); - return new ResolverListAdapter(context, payloadIntents, initialIntents, rList, - filterLastUsed, createListController(), useLayoutForBrowsables, this, + filterLastUsed, createListController(userHandle), useLayoutForBrowsables, this, isAudioCaptureDevice); } @VisibleForTesting - protected ResolverListController createListController() { + protected ResolverListController createListController(UserHandle userHandle) { return new ResolverListController( this, mPm, getTargetIntent(), getReferrerPackageName(), - mLaunchedFromUid); + mLaunchedFromUid, + userHandle); } /** @@ -1069,16 +1200,17 @@ public class ResolverActivity extends Activity implements * @return <code>true</code> if the activity is finishing and creation should halt. */ private boolean configureContentView() { - if (mAdapter == null) { + if (mMultiProfilePagerAdapter.getCurrentListAdapter() == null) { throw new IllegalStateException("mAdapter cannot be null."); } - boolean rebuildCompleted = mAdapter.rebuildList(); + boolean rebuildCompleted = mMultiProfilePagerAdapter.getCurrentListAdapter().rebuildList(); if (useLayoutWithDefault()) { mLayoutId = R.layout.resolver_list_with_default; } else { mLayoutId = getLayoutResource(); } setContentView(mLayoutId); + mMultiProfilePagerAdapter.setupViewPager(findViewById(R.id.profile_pager)); return postRebuildList(rebuildCompleted); } @@ -1099,14 +1231,16 @@ public class ResolverActivity extends Activity implements */ final boolean postRebuildListInternal(boolean rebuildCompleted) { - int count = mAdapter.getUnfilteredCount(); + int count = mMultiProfilePagerAdapter.getCurrentListAdapter().getUnfilteredCount(); // We only rebuild asynchronously when we have multiple elements to sort. In the case where // we're already done, we can check if we should auto-launch immediately. if (rebuildCompleted) { - if (count == 1 && mAdapter.getOtherProfile() == null) { + if (count == 1 + && mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile() == null) { // Only one target, so we're a candidate to auto-launch! - final TargetInfo target = mAdapter.targetInfoForPosition(0, false); + final TargetInfo target = mMultiProfilePagerAdapter.getCurrentListAdapter() + .targetInfoForPosition(0, false); if (shouldAutoLaunchSingleChoice(target)) { safelyStartActivity(target); mPackageMonitor.unregister(); @@ -1117,37 +1251,32 @@ public class ResolverActivity extends Activity implements } } - boolean isAdapterViewVisible = true; - if (count == 0 && mAdapter.getPlaceholderCount() == 0) { + setupViewVisibilities(count); + return false; + } + + private void setupViewVisibilities(int count) { + if (count == 0 + && mMultiProfilePagerAdapter.getCurrentListAdapter().getPlaceholderCount() == 0) { final TextView emptyView = findViewById(R.id.empty); emptyView.setVisibility(View.VISIBLE); - isAdapterViewVisible = false; + findViewById(R.id.profile_pager).setVisibility(View.GONE); + } else { + onPrepareAdapterView(mMultiProfilePagerAdapter.getCurrentListAdapter()); } - - onPrepareAdapterView(mAdapter, isAdapterViewVisible); - return false; } /** * Prepare the scrollable view which consumes data in the list adapter. * @param adapter The adapter used to provide data to item views. - * @param isVisible True if the scrollable view should be visible; false, otherwise. */ - public void onPrepareAdapterView(ResolverListAdapter adapter, boolean isVisible) { - mAdapterView = findViewById(R.id.resolver_list); - if (!isVisible) { - mAdapterView.setVisibility(View.GONE); - return; - } - mAdapterView.setVisibility(View.VISIBLE); + public void onPrepareAdapterView(ResolverListAdapter adapter) { + mMultiProfilePagerAdapter.getCurrentAdapterView().setVisibility(View.VISIBLE); final boolean useHeader = adapter.hasFilteredItem(); - final ListView listView = mAdapterView instanceof ListView ? (ListView) mAdapterView : null; - - mAdapterView.setAdapter(mAdapter); - + final ListView listView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView(); final ItemClickListener listener = new ItemClickListener(); - mAdapterView.setOnItemClickListener(listener); - mAdapterView.setOnItemLongClickListener(listener); + listView.setOnItemClickListener(listener); + listView.setOnItemLongClickListener(listener); if (mSupportsAlwaysUseOption || mUseLayoutForBrowsables) { listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE); @@ -1166,7 +1295,8 @@ public class ResolverActivity extends Activity implements * Configure the area above the app selection list (title, content preview, etc). */ public void setHeader() { - if (mAdapter.getCount() == 0 && mAdapter.getPlaceholderCount() == 0) { + if (mMultiProfilePagerAdapter.getCurrentListAdapter().getCount() == 0 + && mMultiProfilePagerAdapter.getCurrentListAdapter().getPlaceholderCount() == 0) { final TextView titleView = findViewById(R.id.title); if (titleView != null) { titleView.setVisibility(View.GONE); @@ -1187,11 +1317,11 @@ public class ResolverActivity extends Activity implements final ImageView iconView = findViewById(R.id.icon); if (iconView != null) { - mAdapter.loadFilteredItemIconTaskAsync(iconView); + mMultiProfilePagerAdapter.getCurrentListAdapter().loadFilteredItemIconTaskAsync(iconView); } } - private void resetButtonBar() { + protected void resetButtonBar() { if (!mSupportsAlwaysUseOption && !mUseLayoutForBrowsables) { return; } @@ -1215,24 +1345,27 @@ public class ResolverActivity extends Activity implements } private void resetAlwaysOrOnceButtonBar() { - if (useLayoutWithDefault() - && mAdapter.getFilteredPosition() != ListView.INVALID_POSITION) { - setAlwaysButtonEnabled(true, mAdapter.getFilteredPosition(), false); + int filteredPosition = mMultiProfilePagerAdapter.getCurrentListAdapter() + .getFilteredPosition(); + if (useLayoutWithDefault() && filteredPosition != ListView.INVALID_POSITION) { + setAlwaysButtonEnabled(true, filteredPosition, false); mOnceButton.setEnabled(true); return; } // When the items load in, if an item was already selected, enable the buttons - if (mAdapterView != null - && mAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) { - setAlwaysButtonEnabled(true, mAdapterView.getCheckedItemPosition(), true); + ListView currentAdapterView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView(); + if (currentAdapterView != null + && currentAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) { + setAlwaysButtonEnabled(true, currentAdapterView.getCheckedItemPosition(), true); mOnceButton.setEnabled(true); } } @Override // ResolverListCommunicator public boolean useLayoutWithDefault() { - return mSupportsAlwaysUseOption && mAdapter.hasFilteredItem(); + return mSupportsAlwaysUseOption + && mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem(); } /** @@ -1256,7 +1389,7 @@ public class ResolverActivity extends Activity implements @Override // ResolverListCommunicator public void onHandlePackagesChanged() { - if (mAdapter.getCount() == 0) { + if (mMultiProfilePagerAdapter.getCurrentListAdapter().getCount() == 0) { // We no longer have any items... just finish the activity. finish(); } @@ -1331,11 +1464,14 @@ public class ResolverActivity extends Activity implements return; } // If we're still loading, we can't yet enable the buttons. - if (mAdapter.resolveInfoForPosition(position, true) == null) { + if (mMultiProfilePagerAdapter.getCurrentListAdapter() + .resolveInfoForPosition(position, true) == null) { return; } - final int checkedPos = mAdapterView.getCheckedItemPosition(); + ListView currentAdapterView = + (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView(); + final int checkedPos = currentAdapterView.getCheckedItemPosition(); final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION; if (!useLayoutWithDefault() && (!hasValidSelection || mLastSelected != checkedPos) @@ -1343,7 +1479,7 @@ public class ResolverActivity extends Activity implements setAlwaysButtonEnabled(hasValidSelection, checkedPos, true); mOnceButton.setEnabled(hasValidSelection); if (hasValidSelection) { - mAdapterView.smoothScrollToPosition(checkedPos); + currentAdapterView.smoothScrollToPosition(checkedPos); } mLastSelected = checkedPos; } else { @@ -1361,7 +1497,8 @@ public class ResolverActivity extends Activity implements // Header views don't count. return false; } - ResolveInfo ri = mAdapter.resolveInfoForPosition(position, true); + ResolveInfo ri = mMultiProfilePagerAdapter.getCurrentListAdapter() + .resolveInfoForPosition(position, true); showTargetDetails(ri); return true; } @@ -1401,7 +1538,8 @@ public class ResolverActivity extends Activity implements final ResolverActivity ra = (ResolverActivity) getActivity(); if (ra != null) { - final TargetInfo ti = ra.mAdapter.getItem(selections[0].getIndex()); + final TargetInfo ti = ra.mMultiProfilePagerAdapter.getCurrentListAdapter() + .getItem(selections[0].getIndex()); if (ra.onTargetSelected(ti, false)) { ra.mPickOptionRequest = null; ra.finish(); diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java index bb7ca358f815..48064da7c35c 100644 --- a/core/java/com/android/internal/app/ResolverListAdapter.java +++ b/core/java/com/android/internal/app/ResolverListAdapter.java @@ -37,7 +37,6 @@ import android.graphics.ColorMatrixColorFilter; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; -import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -81,7 +80,7 @@ public class ResolverListAdapter extends BaseAdapter { // This one is the list that the Adapter will actually present. List<DisplayResolveInfo> mDisplayList; - List<ResolvedComponentInfo> mUnfilteredResolveList; + private List<ResolvedComponentInfo> mUnfilteredResolveList; private int mLastChosenPosition = -1; private boolean mFilterLastUsed; @@ -162,6 +161,10 @@ public class ResolverListAdapter extends BaseAdapter { mResolverListController.updateChooserCounts(packageName, userId, action); } + List<ResolvedComponentInfo> getUnfilteredResolveList() { + return mUnfilteredResolveList; + } + /** * @return true if all items in the display list are defined as browsers by * ResolveInfo.handleAllWebDataURI @@ -576,7 +579,7 @@ public class ResolverListAdapter extends BaseAdapter { Drawable loadIconForResolveInfo(ResolveInfo ri) { // Load icons based on the current process. If in work profile icons should be badged. - return makePresentationGetter(ri).getIcon(Process.myUserHandle()); + return makePresentationGetter(ri).getIcon(mResolverListController.getUserHandle()); } void loadFilteredItemIconTaskAsync(@NonNull ImageView iconView) { diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java index b456ca00fe2b..abd3eb2453df 100644 --- a/core/java/com/android/internal/app/ResolverListController.java +++ b/core/java/com/android/internal/app/ResolverListController.java @@ -28,6 +28,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.RemoteException; +import android.os.UserHandle; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -55,6 +56,7 @@ public class ResolverListController { private static final String TAG = "ResolverListController"; private static final boolean DEBUG = false; + private final UserHandle mUserHandle; private AbstractResolverComparator mResolverComparator; private boolean isComputed = false; @@ -64,8 +66,9 @@ public class ResolverListController { PackageManager pm, Intent targetIntent, String referrerPackage, - int launchedFromUid) { - this(context, pm, targetIntent, referrerPackage, launchedFromUid, + int launchedFromUid, + UserHandle userHandle) { + this(context, pm, targetIntent, referrerPackage, launchedFromUid, userHandle, new ResolverRankerServiceResolverComparator( context, targetIntent, referrerPackage, null)); } @@ -76,12 +79,14 @@ public class ResolverListController { Intent targetIntent, String referrerPackage, int launchedFromUid, + UserHandle userHandle, AbstractResolverComparator resolverComparator) { mContext = context; mpm = pm; mLaunchedFromUid = launchedFromUid; mTargetIntent = targetIntent; mReferrerPackage = referrerPackage; + mUserHandle = userHandle; mResolverComparator = resolverComparator; } @@ -116,7 +121,8 @@ public class ResolverListController { || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) { flags |= PackageManager.MATCH_INSTANT; } - final List<ResolveInfo> infos = mpm.queryIntentActivities(intent, flags); + final List<ResolveInfo> infos = mpm.queryIntentActivitiesAsUser(intent, flags, + mUserHandle); if (infos != null) { if (resolvedComponents == null) { resolvedComponents = new ArrayList<>(); @@ -127,6 +133,10 @@ public class ResolverListController { return resolvedComponents; } + UserHandle getUserHandle() { + return mUserHandle; + } + @VisibleForTesting public void addResolveListDedupe(List<ResolverActivity.ResolvedComponentInfo> into, Intent intent, diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java new file mode 100644 index 000000000000..9e814ab5d0aa --- /dev/null +++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.app; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.ListView; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.widget.PagerAdapter; + +/** + * A {@link PagerAdapter} which describes the work and personal profile intent resolver screens. + */ +@VisibleForTesting +public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerAdapter { + + private final ResolverProfileDescriptor[] mItems; + + ResolverMultiProfilePagerAdapter(Context context, + ResolverListAdapter adapter) { + super(context, /* currentPage */ 0); + mItems = new ResolverProfileDescriptor[] { + createProfileDescriptor(adapter) + }; + } + + ResolverMultiProfilePagerAdapter(Context context, + ResolverListAdapter personalAdapter, + ResolverListAdapter workAdapter, + @Profile int defaultProfile) { + super(context, /* currentPage */ defaultProfile); + mItems = new ResolverProfileDescriptor[] { + createProfileDescriptor(personalAdapter), + createProfileDescriptor(workAdapter) + }; + } + + private ResolverProfileDescriptor createProfileDescriptor( + ResolverListAdapter adapter) { + final LayoutInflater inflater = LayoutInflater.from(getContext()); + final ViewGroup rootView = + (ViewGroup) inflater.inflate(R.layout.resolver_list_per_profile, null, false); + return new ResolverProfileDescriptor(rootView, adapter); + } + + ListView getListViewForIndex(int index) { + return getItem(index).listView; + } + + @Override + ResolverProfileDescriptor getItem(int pageIndex) { + return mItems[pageIndex]; + } + + @Override + int getItemCount() { + return mItems.length; + } + + @Override + void setupListAdapter(int pageIndex) { + final ListView listView = getItem(pageIndex).listView; + listView.setAdapter(getItem(pageIndex).resolverListAdapter); + } + + @Override + ResolverListAdapter getAdapterForIndex(int pageIndex) { + return mItems[pageIndex].resolverListAdapter; + } + + @Override + @VisibleForTesting + public ResolverListAdapter getCurrentListAdapter() { + return getAdapterForIndex(getCurrentPage()); + } + + @Override + ResolverListAdapter getCurrentRootAdapter() { + return getCurrentListAdapter(); + } + + @Override + ListView getCurrentAdapterView() { + return getListViewForIndex(getCurrentPage()); + } + + class ResolverProfileDescriptor extends ProfileDescriptor { + private ResolverListAdapter resolverListAdapter; + final ListView listView; + ResolverProfileDescriptor(ViewGroup rootView, ResolverListAdapter adapter) { + super(rootView); + resolverListAdapter = adapter; + listView = rootView.findViewById(R.id.resolver_list); + } + } +} diff --git a/core/java/com/android/internal/app/WrapHeightViewPager.java b/core/java/com/android/internal/app/WrapHeightViewPager.java new file mode 100644 index 000000000000..b017bb44d751 --- /dev/null +++ b/core/java/com/android/internal/app/WrapHeightViewPager.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.app; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; + +import com.android.internal.widget.ViewPager; + +/** + * A {@link ViewPager} which wraps around its first child's height. + * <p>Normally {@link ViewPager} instances expand their height to cover all remaining space in + * the layout. + * <p>This class is used for the intent resolver picker's tabbed view to maintain + * consistency with the previous behavior. + */ +public class WrapHeightViewPager extends ViewPager { + + public WrapHeightViewPager(Context context) { + super(context); + } + + public WrapHeightViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public WrapHeightViewPager(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public WrapHeightViewPager(Context context, AttributeSet attrs, + int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + // TODO(arangelov): When we have multiple pages, the height should wrap to the currently + // displayed page. Investigate whether onMeasure is called when changing a page, and instead + // of getChildAt(0), use the currently displayed one. + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.AT_MOST) { + return; + } + widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY); + int height = getMeasuredHeight(); + if (getChildCount() > 0) { + View firstChild = getChildAt(0); + firstChild.measure(widthMeasureSpec, + MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); + height = firstChild.getMeasuredHeight(); + } + heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } +} diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 0847fbdd2291..f5fae1932cc4 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -28,9 +28,9 @@ import static android.system.OsConstants.S_IXOTH; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.Package; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.parsing.AndroidPackage; import android.os.Build; import android.os.SELinux; import android.system.ErrnoException; @@ -87,11 +87,12 @@ public class NativeLibraryHelper { } } - public static Handle create(Package pkg) throws IOException { - return create(pkg.getAllCodePaths(), - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0, - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0, - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0); + public static Handle create(AndroidPackage pkg) throws IOException { + return create( + pkg.makeListAllCodePaths(), + (pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0, + (pkg.getFlags() & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0, + (pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0); } public static Handle create(PackageLite lite) throws IOException { @@ -455,7 +456,7 @@ public class NativeLibraryHelper { * @param useIsaSubdir Whether or not to set up a sub dir for the ISA. * @return ABI code if installation succeeds or error code if installation fails. */ - public static int configureNativeBinariesForSupportedAbi(Package pkg, Handle handle, + public static int configureNativeBinariesForSupportedAbi(AndroidPackage pkg, Handle handle, File libraryRoot, String[] abiList, boolean useIsaSubdir) { // TODO(b/136132412): Implement this. return -1; diff --git a/core/java/com/android/internal/infra/AndroidFuture.java b/core/java/com/android/internal/infra/AndroidFuture.java index c8929e93f030..d78bd73b080b 100644 --- a/core/java/com/android/internal/infra/AndroidFuture.java +++ b/core/java/com/android/internal/infra/AndroidFuture.java @@ -513,6 +513,11 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable try { result = get(); } catch (Exception t) { + // Exceptions coming out of get() are wrapped in ExecutionException, which is not + // handled by Parcel. + if (t instanceof ExecutionException && t.getCause() instanceof Exception) { + t = (Exception) t.getCause(); + } dest.writeBoolean(true); dest.writeException(t); return; diff --git a/core/java/com/android/internal/infra/TEST_MAPPING b/core/java/com/android/internal/infra/TEST_MAPPING index 3781d637f68c..3de107e892b6 100644 --- a/core/java/com/android/internal/infra/TEST_MAPPING +++ b/core/java/com/android/internal/infra/TEST_MAPPING @@ -6,10 +6,18 @@ { "name": "CtsPermissionTestCases", "options": [ - { - "include-filter": "android.permission.cts.PermissionControllerTest" - } + { + "include-filter": "android.permission.cts.PermissionControllerTest" + } + ] + }, + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "com.android.internal.infra." + } ] } ] -}
\ No newline at end of file +} diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index fd3cd42b07a1..a21187165c65 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -30,8 +30,10 @@ import android.os.SystemProperties; import android.os.Trace; import android.util.Log; import android.util.Slog; + import com.android.internal.logging.AndroidConfig; import com.android.server.NetworkManagementSocketTagger; + import dalvik.system.RuntimeHooks; import dalvik.system.VMRuntime; @@ -374,9 +376,6 @@ public class RuntimeInit { // leftover running threads to crash before the process actually exits. nativeSetExitWithoutCleanup(true); - // We want to be fairly aggressive about heap utilization, to avoid - // holding on to a lot of memory that isn't needed. - VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); final Arguments args = new Arguments(argv); diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 821022f1f917..bc8019796d22 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -600,6 +600,14 @@ public class ArrayUtils { return cur; } + public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, int index, T val) { + if (cur == null) { + cur = new ArrayList<>(); + } + cur.add(index, val); + return cur; + } + public static @Nullable <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) { if (cur == null) { return null; diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java index 4165f202998c..4dac5427095b 100644 --- a/core/java/com/android/internal/util/CollectionUtils.java +++ b/core/java/com/android/internal/util/CollectionUtils.java @@ -308,6 +308,17 @@ public class CollectionUtils { } /** + * @see #add(List, Object) + */ + public static @NonNull <K, V> Map<K, V> add(@Nullable Map<K, V> map, K key, V value) { + if (map == null || map == Collections.emptyMap()) { + map = new ArrayMap<>(); + } + map.put(key, value); + return map; + } + + /** * Similar to {@link List#remove}, but with support for list values of {@code null} and * {@link Collections#emptyList} */ diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java index 731b93c18b09..3fff5c233890 100644 --- a/core/java/com/android/internal/util/Preconditions.java +++ b/core/java/com/android/internal/util/Preconditions.java @@ -102,6 +102,24 @@ public class Preconditions { } /** + * Ensures that an string reference passed as a parameter to the calling method is not empty. + * + * @param string an string reference + * @param messageTemplate a printf-style message template to use if the check fails; will be + * converted to a string using {@link String#format(String, Object...)} + * @param messageArgs arguments for {@code messageTemplate} + * @return the string reference that was validated + * @throws IllegalArgumentException if {@code string} is empty + */ + public static @NonNull <T extends CharSequence> T checkStringNotEmpty( + final T string, final String messageTemplate, final Object... messageArgs) { + if (TextUtils.isEmpty(string)) { + throw new IllegalArgumentException(String.format(messageTemplate, messageArgs)); + } + return string; + } + + /** * Ensures that an object reference passed as a parameter to the calling * method is not null. * diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 897b982406dc..13cc98be5d5a 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -43,7 +43,7 @@ interface ILockSettings { long getLong(in String key, in long defaultValue, in int userId); @UnsupportedAppUsage String getString(in String key, in String defaultValue, in int userId); - boolean setLockCredential(in LockscreenCredential credential, in LockscreenCredential savedCredential, int userId, boolean allowUntrustedChange); + boolean setLockCredential(in LockscreenCredential credential, in LockscreenCredential savedCredential, int userId); void resetKeyStore(int userId); VerifyCredentialResponse checkCredential(in LockscreenCredential credential, int userId, in ICheckCredentialProgressCallback progressCallback); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index b534213ec859..cff39f120dd7 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -636,35 +636,16 @@ public class LockPatternUtils { * * @param newCredential The new credential to save * @param savedCredential The current credential - * @param userId the user whose lockscreen credential is to be changed - * - * @return whether this method saved the new password successfully or not. This flow will fail - * and return false if the given credential is wrong. - * @throws RuntimeException if password change encountered an unrecoverable error. - */ - public boolean setLockCredential(@NonNull LockscreenCredential newCredential, - @NonNull LockscreenCredential savedCredential, int userId) { - return setLockCredential(newCredential, savedCredential, userId, false); - } - - /** - * Save a new lockscreen credential. - * <p> This method will fail (returning {@code false}) if the previously saved pattern provided - * is incorrect and allowUntrustedChange is false, or if the lockscreen verification is still - * being throttled. - * @param newCredential The new credential to save - * @param savedCredential The current credential * @param userHandle the user whose lockscreen credential is to be changed - * @param allowUntrustedChange whether we want to allow saving a new pattern if the existing - * credentialt being provided is incorrect. * * @return whether this method saved the new password successfully or not. This flow will fail - * and return false if the given credential is wrong and allowUntrustedChange is false. + * and return false if the given credential is wrong. * @throws RuntimeException if password change encountered an unrecoverable error. + * @throws UnsupportedOperationException secure lockscreen is not supported on this device. + * @throws IllegalArgumentException if new credential is too short. */ public boolean setLockCredential(@NonNull LockscreenCredential newCredential, - @NonNull LockscreenCredential savedCredential, int userHandle, - boolean allowUntrustedChange) { + @NonNull LockscreenCredential savedCredential, int userHandle) { if (!hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires the lock screen feature."); @@ -672,8 +653,7 @@ public class LockPatternUtils { newCredential.checkLength(); try { - if (!getLockSettings().setLockCredential( - newCredential, savedCredential, userHandle, allowUntrustedChange)) { + if (!getLockSettings().setLockCredential(newCredential, savedCredential, userHandle)) { return false; } } catch (RemoteException e) { diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java index dc4f09a2af6f..13bfc1bf72b8 100644 --- a/core/java/com/android/server/BootReceiver.java +++ b/core/java/com/android/server/BootReceiver.java @@ -66,10 +66,15 @@ import org.xmlpull.v1.XmlSerializer; public class BootReceiver extends BroadcastReceiver { private static final String TAG = "BootReceiver"; + private static final String TAG_TRUNCATED = "[[TRUNCATED]]\n"; + // Maximum size of a logged event (files get truncated if they're longer). // Give userdebug builds a larger max to capture extra debug, esp. for last_kmsg. private static final int LOG_SIZE = SystemProperties.getInt("ro.debuggable", 0) == 1 ? 98304 : 65536; + private static final int LASTK_LOG_SIZE = + SystemProperties.getInt("ro.debuggable", 0) == 1 ? 196608 : 65536; + private static final int GMSCORE_LASTK_LOG_SIZE = 196608; private static final File TOMBSTONE_DIR = new File("/data/tombstones"); private static final String TAG_TOMBSTONE = "SYSTEM_TOMBSTONE"; @@ -224,12 +229,12 @@ public class BootReceiver extends BroadcastReceiver { if (db != null) db.addText("SYSTEM_BOOT", headers); // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile()) - addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter, - "/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG"); - addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter, - "/sys/fs/pstore/console-ramoops", -LOG_SIZE, "SYSTEM_LAST_KMSG"); - addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter, - "/sys/fs/pstore/console-ramoops-0", -LOG_SIZE, "SYSTEM_LAST_KMSG"); + addLastkToDropBox(db, timestamps, headers, lastKmsgFooter, + "/proc/last_kmsg", -LASTK_LOG_SIZE, "SYSTEM_LAST_KMSG"); + addLastkToDropBox(db, timestamps, headers, lastKmsgFooter, + "/sys/fs/pstore/console-ramoops", -LASTK_LOG_SIZE, "SYSTEM_LAST_KMSG"); + addLastkToDropBox(db, timestamps, headers, lastKmsgFooter, + "/sys/fs/pstore/console-ramoops-0", -LASTK_LOG_SIZE, "SYSTEM_LAST_KMSG"); addFileToDropBox(db, timestamps, headers, "/cache/recovery/log", -LOG_SIZE, "SYSTEM_RECOVERY_LOG"); addFileToDropBox(db, timestamps, headers, "/cache/recovery/last_kmsg", @@ -278,6 +283,23 @@ public class BootReceiver extends BroadcastReceiver { sTombstoneObserver.startWatching(); } + private static void addLastkToDropBox( + DropBoxManager db, HashMap<String, Long> timestamps, + String headers, String footers, String filename, int maxSize, + String tag) throws IOException { + int extraSize = headers.length() + TAG_TRUNCATED.length() + footers.length(); + // GMSCore will do 2nd truncation to be 192KiB + // LASTK_LOG_SIZE + extraSize must be less than GMSCORE_LASTK_LOG_SIZE + if (LASTK_LOG_SIZE + extraSize > GMSCORE_LASTK_LOG_SIZE) { + if (GMSCORE_LASTK_LOG_SIZE > extraSize) { + maxSize = -(GMSCORE_LASTK_LOG_SIZE - extraSize); + } else { + maxSize = 0; + } + } + addFileWithFootersToDropBox(db, timestamps, headers, footers, filename, maxSize, tag); + } + private static void addFileToDropBox( DropBoxManager db, HashMap<String, Long> timestamps, String headers, String filename, int maxSize, String tag) throws IOException { @@ -301,7 +323,7 @@ public class BootReceiver extends BroadcastReceiver { timestamps.put(filename, fileTime); - String fileContents = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n"); + String fileContents = FileUtils.readTextFile(file, maxSize, TAG_TRUNCATED); String text = headers + fileContents + footers; // Create an additional report for system server native crashes, with a special tag. if (tag.equals(TAG_TOMBSTONE) && fileContents.contains(">>> system_server <<<")) { @@ -345,7 +367,7 @@ public class BootReceiver extends BroadcastReceiver { timestamps.put(tag, fileTime); - String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n"); + String log = FileUtils.readTextFile(file, maxSize, TAG_TRUNCATED); StringBuilder sb = new StringBuilder(); for (String line : log.split("\n")) { if (line.contains("audit")) { @@ -370,7 +392,7 @@ public class BootReceiver extends BroadcastReceiver { long fileTime = file.lastModified(); if (fileTime <= 0) return; // File does not exist - String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n"); + String log = FileUtils.readTextFile(file, maxSize, TAG_TRUNCATED); Pattern pattern = Pattern.compile(FS_STAT_PATTERN); String lines[] = log.split("\n"); int lineNumber = 0; diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 49a73ee7790f..e6232e851253 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -226,7 +226,7 @@ public class SystemConfig { * Map of system pre-defined, uniquely named actors; keys are namespace, * value maps actor name to package name. */ - private ArrayMap<String, ArrayMap<String, String>> mNamedActors = null; + private Map<String, Map<String, String>> mNamedActors = null; public static SystemConfig getInstance() { if (!isSystemProcess()) { @@ -406,7 +406,7 @@ public class SystemConfig { } @NonNull - public Map<String, ? extends Map<String, String>> getNamedActors() { + public Map<String, Map<String, String>> getNamedActors() { return mNamedActors != null ? mNamedActors : Collections.emptyMap(); } @@ -1063,7 +1063,7 @@ public class SystemConfig { mNamedActors = new ArrayMap<>(); } - ArrayMap<String, String> nameToPkgMap = mNamedActors.get(namespace); + Map<String, String> nameToPkgMap = mNamedActors.get(namespace); if (nameToPkgMap == null) { nameToPkgMap = new ArrayMap<>(); mNamedActors.put(namespace, nameToPkgMap); diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 148b0a2799b4..9025c6981fc2 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -144,6 +144,7 @@ cc_library_shared { "android_os_VintfRuntimeInfo.cpp", "android_net_LocalSocketImpl.cpp", "android_net_NetUtils.cpp", + "android_service_incremental_IncrementalDataLoaderService.cpp", "android_util_AssetManager.cpp", "android_util_Binder.cpp", "android_util_StatsLog.cpp", @@ -152,6 +153,7 @@ cc_library_shared { "android_util_StringBlock.cpp", "android_util_XmlBlock.cpp", "android_util_jar_StrictJarFile.cpp", + "android_media_AudioDeviceAddress.cpp", "android_media_AudioEffectDescriptor.cpp", "android_media_AudioRecord.cpp", "android_media_AudioSystem.cpp", @@ -239,6 +241,8 @@ cc_library_shared { "libGLESv1_CM", "libGLESv2", "libGLESv3", + "libincfs", + "libincremental_dataloader", "libvulkan", "libETC1", "libhardware", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 378e125a3a3e..bead0baf9edc 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -86,6 +86,7 @@ extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env); extern int register_android_hardware_UsbRequest(JNIEnv *env); extern int register_android_hardware_location_ActivityRecognitionHardware(JNIEnv* env); +extern int register_android_media_AudioDeviceAddress(JNIEnv *env); extern int register_android_media_AudioEffectDescriptor(JNIEnv *env); extern int register_android_media_AudioRecord(JNIEnv *env); extern int register_android_media_AudioSystem(JNIEnv *env); @@ -150,6 +151,7 @@ extern int register_android_os_UEventObserver(JNIEnv* env); extern int register_android_os_HidlMemory(JNIEnv* env); extern int register_android_os_MemoryFile(JNIEnv* env); extern int register_android_os_SharedMemory(JNIEnv* env); +extern int register_android_service_incremental_IncrementalDataLoaderService(JNIEnv* env); extern int register_android_net_LocalSocketImpl(JNIEnv* env); extern int register_android_net_NetworkUtils(JNIEnv* env); extern int register_android_text_AndroidCharacter(JNIEnv *env); @@ -648,6 +650,7 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX]; std::string fingerprintBuf; char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX]; + char opaqueJniIds[sizeof("-Xopaque-jni-ids:") - 1 + PROPERTY_VALUE_MAX]; char bootImageBuf[sizeof("-Ximage:") - 1 + PROPERTY_VALUE_MAX]; // Read if we are using the profile configuration, do this at the start since the last ART args @@ -839,6 +842,14 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p "default"); } + // Only pass an explicit opaque-jni-ids to apps forked from zygote + if (zygote) { + parseRuntimeOption("dalvik.vm.opaque-jni-ids", + opaqueJniIds, + "-Xopaque-jni-ids:", + "swapable"); + } + parseRuntimeOption("dalvik.vm.lockprof.threshold", lockProfThresholdBuf, "-Xlockprofthreshold:"); @@ -1442,6 +1453,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_NativeHandle), REG_JNI(register_android_os_VintfObject), REG_JNI(register_android_os_VintfRuntimeInfo), + REG_JNI(register_android_service_incremental_IncrementalDataLoaderService), REG_JNI(register_android_view_DisplayEventReceiver), REG_JNI(register_android_view_RenderNodeAnimator), REG_JNI(register_android_view_InputApplicationHandle), @@ -1501,6 +1513,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_hardware_UsbDeviceConnection), REG_JNI(register_android_hardware_UsbRequest), REG_JNI(register_android_hardware_location_ActivityRecognitionHardware), + REG_JNI(register_android_media_AudioDeviceAddress), REG_JNI(register_android_media_AudioEffectDescriptor), REG_JNI(register_android_media_AudioSystem), REG_JNI(register_android_media_AudioRecord), diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp index f3a626e1e193..5d13cf82141b 100644 --- a/core/jni/android_content_res_ApkAssets.cpp +++ b/core/jni/android_content_res_ApkAssets.cpp @@ -32,6 +32,11 @@ using ::android::base::unique_fd; namespace android { +static struct overlayableinfo_offsets_t { + jclass classObject; + jmethodID constructor; +} gOverlayableInfoOffsets; + static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, jstring java_path, jboolean system, jboolean force_shared_lib, jboolean overlay, jboolean for_loader) { ScopedUtfChars path(env, java_path); @@ -222,12 +227,9 @@ static jobject NativeGetOverlayableInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr return 0; } - jclass overlayable_class = env->FindClass("android/content/om/OverlayableInfo"); - jmethodID overlayable_constructor = env->GetMethodID(overlayable_class, "<init>", - "(Ljava/lang/String;Ljava/lang/String;I)V"); return env->NewObject( - overlayable_class, - overlayable_constructor, + gOverlayableInfoOffsets.classObject, + gOverlayableInfoOffsets.constructor, overlayable_name, actor_string ); @@ -267,6 +269,11 @@ static const JNINativeMethod gApkAssetsMethods[] = { }; int register_android_content_res_ApkAssets(JNIEnv* env) { + jclass overlayableInfoClass = FindClassOrDie(env, "android/content/om/OverlayableInfo"); + gOverlayableInfoOffsets.classObject = MakeGlobalRefOrDie(env, overlayableInfoClass); + gOverlayableInfoOffsets.constructor = GetMethodIDOrDie(env, gOverlayableInfoOffsets.classObject, + "<init>", "(Ljava/lang/String;Ljava/lang/String;)V"); + return RegisterMethodsOrDie(env, "android/content/res/ApkAssets", gApkAssetsMethods, arraysize(gApkAssetsMethods)); } diff --git a/core/jni/android_media_AudioDeviceAddress.cpp b/core/jni/android_media_AudioDeviceAddress.cpp new file mode 100644 index 000000000000..5f39f7efb6a2 --- /dev/null +++ b/core/jni/android_media_AudioDeviceAddress.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "core_jni_helpers.h" +#include "android_media_AudioDeviceAddress.h" +#include "android_media_AudioErrors.h" + +#include <media/AudioDeviceTypeAddr.h> + +using namespace android; + +static jclass gAudioDeviceAddressClass; +static jmethodID gAudioDeviceAddressCstor; + +namespace android { + +jint createAudioDeviceAddressFromNative( + JNIEnv *env, jobject *jAudioDeviceAddress, + const AudioDeviceTypeAddr *devTypeAddr) { + jint jStatus = (jint)AUDIO_JAVA_SUCCESS; + jint jNativeType = (jint)devTypeAddr->mType; + ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(devTypeAddr->mAddress.data())); + + *jAudioDeviceAddress = env->NewObject(gAudioDeviceAddressClass, gAudioDeviceAddressCstor, + jNativeType, jAddress.get()); + + return jStatus; +} + +} + +int register_android_media_AudioDeviceAddress(JNIEnv *env) +{ + jclass audioDeviceTypeAddressClass = FindClassOrDie(env, "android/media/AudioDeviceAddress"); + gAudioDeviceAddressClass = MakeGlobalRefOrDie(env, audioDeviceTypeAddressClass); + gAudioDeviceAddressCstor = GetMethodIDOrDie(env, audioDeviceTypeAddressClass, "<init>", + "(ILjava/lang/String;)V"); + + return 0; +} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java b/core/jni/android_media_AudioDeviceAddress.h index faa6e9cff2b2..c66b17978776 100644 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java +++ b/core/jni/android_media_AudioDeviceAddress.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,19 +12,22 @@ * 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.frameworks.coretests; +#ifndef ANDROID_MEDIA_AUDIODEVICEADDRESS_H +#define ANDROID_MEDIA_AUDIODEVICEADDRESS_H + +#include <system/audio.h> +#include <media/AudioDeviceTypeAddr.h> + +#include "jni.h" + +namespace android { -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; +// Create a Java AudioDeviceAddress instance from a C++ AudioDeviceTypeAddress -public class FirstChildTestService extends Service { +extern jint createAudioDeviceAddressFromNative(JNIEnv *env, jobject *jAudioDeviceAddress, + const AudioDeviceTypeAddr *devTypeAddr); +} // namespace android - @Override - public IBinder onBind(Intent intent) { - return null; - } -} +#endif
\ No newline at end of file diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 01f9d0b0cde5..79cf0191057d 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -26,19 +26,19 @@ #include <nativehelper/JNIHelp.h> #include "core_jni_helpers.h" +#include "android_media_AudioAttributes.h" +#include "android_media_AudioDeviceAddress.h" +#include "android_media_AudioEffectDescriptor.h" +#include "android_media_AudioErrors.h" +#include "android_media_AudioFormat.h" +#include "android_media_MicrophoneInfo.h" #include <audiomanager/AudioManager.h> -#include <media/AudioDeviceTypeAddr.h> -#include <media/AudioSystem.h> #include <media/AudioPolicy.h> +#include <media/AudioSystem.h> #include <media/MicrophoneInfo.h> #include <nativehelper/ScopedLocalRef.h> #include <system/audio.h> #include <system/audio_policy.h> -#include "android_media_AudioEffectDescriptor.h" -#include "android_media_AudioFormat.h" -#include "android_media_AudioErrors.h" -#include "android_media_MicrophoneInfo.h" -#include "android_media_AudioAttributes.h" // ---------------------------------------------------------------------------- @@ -2254,9 +2254,9 @@ static jint android_media_AudioSystem_setAudioHalPids(JNIEnv *env, jobject clazz, jintArray jPids) { if (jPids == NULL) { - return (jint)AUDIO_JAVA_BAD_VALUE; + return (jint) AUDIO_JAVA_BAD_VALUE; } - pid_t *nPidsArray = (pid_t *)env->GetIntArrayElements(jPids, NULL); + pid_t *nPidsArray = (pid_t *) env->GetIntArrayElements(jPids, NULL); std::vector<pid_t> nPids(nPidsArray, nPidsArray + env->GetArrayLength(jPids)); status_t status = AudioSystem::setAudioHalPids(nPids); env->ReleaseIntArrayElements(jPids, nPidsArray, 0); @@ -2270,6 +2270,48 @@ android_media_AudioSystem_isCallScreeningModeSupported(JNIEnv *env, jobject thiz return AudioSystem::isCallScreenModeSupported(); } +static jint +android_media_AudioSystem_setPreferredDeviceForStrategy(JNIEnv *env, jobject thiz, + jint strategy, jint deviceType, jstring deviceAddress) { + + const char *c_address = env->GetStringUTFChars(deviceAddress, NULL); + int status = check_AudioSystem_Command( + AudioSystem::setPreferredDeviceForStrategy((product_strategy_t) strategy, + AudioDeviceTypeAddr(deviceType, c_address))); + env->ReleaseStringUTFChars(deviceAddress, c_address); + return (jint) status; +} + +static jint +android_media_AudioSystem_removePreferredDeviceForStrategy(JNIEnv *env, jobject thiz, jint strategy) +{ + return (jint) check_AudioSystem_Command( + AudioSystem::removePreferredDeviceForStrategy((product_strategy_t) strategy)); +} + +static jint +android_media_AudioSystem_getPreferredDeviceForStrategy(JNIEnv *env, jobject thiz, + jint strategy, jobjectArray jDeviceArray) +{ + if (jDeviceArray == nullptr || env->GetArrayLength(jDeviceArray) != 1) { + ALOGE("%s invalid array to store AudioDeviceAddress", __FUNCTION__); + return (jint)AUDIO_JAVA_BAD_VALUE; + } + + AudioDeviceTypeAddr elDevice; + status_t status = check_AudioSystem_Command( + AudioSystem::getPreferredDeviceForStrategy((product_strategy_t) strategy, elDevice)); + if (status != NO_ERROR) { + return (jint) status; + } + jobject jAudioDeviceAddress = NULL; + jint jStatus = createAudioDeviceAddressFromNative(env, &jAudioDeviceAddress, &elDevice); + if (jStatus == AUDIO_JAVA_SUCCESS) { + env->SetObjectArrayElement(jDeviceArray, 0, jAudioDeviceAddress); + } + return jStatus; +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { @@ -2350,6 +2392,9 @@ static const JNINativeMethod gMethods[] = { {"setRttEnabled", "(Z)I", (void *)android_media_AudioSystem_setRttEnabled}, {"setAudioHalPids", "([I)I", (void *)android_media_AudioSystem_setAudioHalPids}, {"isCallScreeningModeSupported", "()Z", (void *)android_media_AudioSystem_isCallScreeningModeSupported}, + {"setPreferredDeviceForStrategy", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setPreferredDeviceForStrategy}, + {"removePreferredDeviceForStrategy", "(I)I", (void *)android_media_AudioSystem_removePreferredDeviceForStrategy}, + {"getPreferredDeviceForStrategy", "(I[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getPreferredDeviceForStrategy}, }; static const JNINativeMethod gEventHandlerMethods[] = { diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp index bd82bd91c55d..0f7611a8ead1 100644 --- a/core/jni/android_os_Trace.cpp +++ b/core/jni/android_os_Trace.cpp @@ -50,10 +50,6 @@ inline static void withString(JNIEnv* env, jstring jstr, F callback) { callback(buffer.data()); } -static jlong android_os_Trace_nativeGetEnabledTags(JNIEnv*, jclass) { - return atrace_get_enabled_tags(); -} - static void android_os_Trace_nativeTraceCounter(JNIEnv* env, jclass, jlong tag, jstring nameStr, jlong value) { withString(env, nameStr, [tag, value](char* str) { @@ -96,9 +92,6 @@ static void android_os_Trace_nativeSetTracingEnabled(JNIEnv*, jclass, jboolean e static const JNINativeMethod gTraceMethods[] = { /* name, signature, funcPtr */ - { "nativeGetEnabledTags", - "()J", - (void*)android_os_Trace_nativeGetEnabledTags }, { "nativeSetAppTracingAllowed", "(Z)V", (void*)android_os_Trace_nativeSetAppTracingAllowed }, @@ -123,6 +116,11 @@ static const JNINativeMethod gTraceMethods[] = { { "nativeAsyncTraceEnd", "(JLjava/lang/String;I)V", (void*)android_os_Trace_nativeAsyncTraceEnd }, + + // ----------- @CriticalNative ---------------- + { "nativeGetEnabledTags", + "()J", + (void*)atrace_get_enabled_tags }, }; int register_android_os_Trace(JNIEnv* env) { diff --git a/core/jni/android_service_incremental_IncrementalDataLoaderService.cpp b/core/jni/android_service_incremental_IncrementalDataLoaderService.cpp new file mode 100644 index 000000000000..f518dd1a5362 --- /dev/null +++ b/core/jni/android_service_incremental_IncrementalDataLoaderService.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "incfs-dls-jni" + +#include <vector> + +#include "core_jni_helpers.h" +#include "incremental_dataloader_ndk.h" +#include "jni.h" + +namespace android { +namespace { + +struct JniIds { + jfieldID dataBlockFileIno; + jfieldID dataBlockBlockIndex; + jfieldID dataBlockDataBytes; + jfieldID dataBlockCompressionType; + + JniIds(JNIEnv* env) { + const auto dataBlock = + FindClassOrDie(env, + "android/service/incremental/" + "IncrementalDataLoaderService$FileSystemConnector$DataBlock"); + dataBlockFileIno = GetFieldIDOrDie(env, dataBlock, "mFileIno", "J"); + dataBlockBlockIndex = + GetFieldIDOrDie(env, dataBlock, "mBlockIndex", "I"); + dataBlockDataBytes = GetFieldIDOrDie(env, dataBlock, "mDataBytes", "[B"); + dataBlockCompressionType = + GetFieldIDOrDie(env, dataBlock, "mCompressionType", "I"); + } +}; + +const JniIds& jniIds(JNIEnv* env) { + static const JniIds ids(env); + return ids; +} + +class ScopedJniArrayCritical { +public: + ScopedJniArrayCritical(JNIEnv* env, jarray array) : mEnv(env), mArr(array) { + mPtr = array ? env->GetPrimitiveArrayCritical(array, nullptr) : nullptr; + } + ~ScopedJniArrayCritical() { + if (mPtr) { + mEnv->ReleasePrimitiveArrayCritical(mArr, mPtr, 0); + mPtr = nullptr; + } + } + + ScopedJniArrayCritical(const ScopedJniArrayCritical&) = delete; + void operator=(const ScopedJniArrayCritical&) = delete; + + ScopedJniArrayCritical(ScopedJniArrayCritical&& other) + : mEnv(other.mEnv), + mArr(std::exchange(mArr, nullptr)), + mPtr(std::exchange(mPtr, nullptr)) {} + ScopedJniArrayCritical& operator=(ScopedJniArrayCritical&& other) { + mEnv = other.mEnv; + mArr = std::exchange(other.mArr, nullptr); + mPtr = std::exchange(other.mPtr, nullptr); + return *this; + } + + void* ptr() const { return mPtr; } + jsize size() const { return mArr ? mEnv->GetArrayLength(mArr) : 0; } + +private: + JNIEnv* mEnv; + jarray mArr; + void* mPtr; +}; + +static jboolean nativeCreateDataLoader(JNIEnv* env, + jobject thiz, + jint storageId, + jobject control, + jobject params, + jobject callback) { + ALOGE("nativeCreateDataLoader: %p/%d, %d, %p, %p, %p", thiz, + env->GetObjectRefType(thiz), storageId, params, control, callback); + return Incremental_DataLoaderService_OnCreate(env, thiz, + storageId, control, params, callback); +} + +static jboolean nativeStartDataLoader(JNIEnv* env, + jobject thiz, + jint storageId) { + ALOGE("nativeStartDataLoader: %p/%d, %d", thiz, env->GetObjectRefType(thiz), + storageId); + return Incremental_DataLoaderService_OnStart(storageId); +} + +static jboolean nativeStopDataLoader(JNIEnv* env, + jobject thiz, + jint storageId) { + ALOGE("nativeStopDataLoader: %p/%d, %d", thiz, env->GetObjectRefType(thiz), + storageId); + return Incremental_DataLoaderService_OnStop(storageId); +} + +static jboolean nativeDestroyDataLoader(JNIEnv* env, + jobject thiz, + jint storageId) { + ALOGE("nativeDestroyDataLoader: %p/%d, %d", thiz, + env->GetObjectRefType(thiz), storageId); + return Incremental_DataLoaderService_OnDestroy(storageId); +} + + +static jboolean nativeOnFileCreated(JNIEnv* env, + jobject thiz, + jint storageId, + jlong inode, + jbyteArray metadata) { + ALOGE("nativeOnFileCreated: %p/%d, %d", thiz, + env->GetObjectRefType(thiz), storageId); + return Incremental_DataLoaderService_OnFileCreated(storageId, inode, metadata); +} + +static jboolean nativeIsFileRangeLoadedNode(JNIEnv* env, + jobject clazz, + jlong self, + jlong node, + jlong start, + jlong end) { + // TODO(b/136132412): implement this + return JNI_FALSE; +} + +static jboolean nativeWriteMissingData(JNIEnv* env, + jobject clazz, + jlong self, + jobjectArray data_block, + jobjectArray hash_blocks) { + const auto& jni = jniIds(env); + auto length = env->GetArrayLength(data_block); + std::vector<incfs_new_data_block> instructions(length); + + // May not call back into Java after even a single jniArrayCritical, so + // let's collect the Java pointers to byte buffers first and lock them in + // memory later. + + std::vector<jbyteArray> blockBuffers(length); + for (int i = 0; i != length; ++i) { + auto& inst = instructions[i]; + auto jniBlock = env->GetObjectArrayElement(data_block, i); + inst.file_ino = env->GetLongField(jniBlock, jni.dataBlockFileIno); + inst.block_index = env->GetIntField(jniBlock, jni.dataBlockBlockIndex); + blockBuffers[i] = (jbyteArray)env->GetObjectField( + jniBlock, jni.dataBlockDataBytes); + inst.compression = (incfs_compression_alg)env->GetIntField( + jniBlock, jni.dataBlockCompressionType); + } + + std::vector<ScopedJniArrayCritical> jniScopedArrays; + jniScopedArrays.reserve(length); + for (int i = 0; i != length; ++i) { + auto buffer = blockBuffers[i]; + jniScopedArrays.emplace_back(env, buffer); + auto& inst = instructions[i]; + inst.data = (uint64_t)jniScopedArrays.back().ptr(); + inst.data_len = jniScopedArrays.back().size(); + } + + auto connector = (IncrementalFilesystemConnectorPtr)self; + if (auto err = Incremental_FilesystemConnector_writeBlocks( + connector, instructions.data(), length); + err < 0) { + jniScopedArrays.clear(); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +static jboolean nativeWriteSignerDataNode(JNIEnv* env, + jobject clazz, + jlong self, + jstring relative_path, + jbyteArray signer_data) { + // TODO(b/136132412): implement this + return JNI_TRUE; +} + +static jbyteArray nativeGetFileMetadataNode(JNIEnv* env, + jobject clazz, + jlong self, + jlong inode) { + auto connector = (IncrementalFilesystemConnectorPtr)self; + std::vector<char> metadata(INCFS_MAX_FILE_ATTR_SIZE); + size_t size = metadata.size(); + if (Incremental_FilesystemConnector_getRawMetadata(connector, inode, + metadata.data(), &size) < 0) { + size = 0; + } + metadata.resize(size); + + auto buffer = env->NewByteArray(metadata.size()); + env->SetByteArrayRegion(buffer, 0, metadata.size(), + (jbyte*)metadata.data()); + return buffer; +} + +static jbyteArray nativeGetFileInfoNode(JNIEnv* env, + jobject clazz, + jlong self, + jlong inode) { + // TODO(b/136132412): implement this + return nullptr; +} + +static jboolean nativeReportStatus(JNIEnv* env, + jobject clazz, + jlong self, + jint status) { + auto listener = (IncrementalStatusListenerPtr)self; + return Incremental_StatusListener_reportStatus(listener, + (IncrementalDataLoaderStatus)status); +} + +static const JNINativeMethod dlc_method_table[] = { + {"nativeCreateDataLoader", + "(ILandroid/os/incremental/IncrementalFileSystemControlParcel;" + "Landroid/os/incremental/IncrementalDataLoaderParamsParcel;" + "Landroid/content/pm/IDataLoaderStatusListener;)Z", + (void*)nativeCreateDataLoader}, + {"nativeStartDataLoader", "(I)Z", (void*)nativeStartDataLoader}, + {"nativeStopDataLoader", "(I)Z", (void*)nativeStopDataLoader}, + {"nativeDestroyDataLoader", "(I)Z", (void*)nativeDestroyDataLoader}, + {"nativeIsFileRangeLoadedNode", "(JJJJ)Z", + (void*)nativeIsFileRangeLoadedNode}, + {"nativeWriteMissingData", + "(J[Landroid/service/incremental/" + "IncrementalDataLoaderService$FileSystemConnector$DataBlock;[Landroid/service/incremental/" + "IncrementalDataLoaderService$FileSystemConnector$HashBlock;)Z", + (void*)nativeWriteMissingData}, + {"nativeWriteSignerDataNode", "(JJ[B)Z", + (void*)nativeWriteSignerDataNode}, + {"nativeGetFileMetadataNode", "(JJ)[B", + (void*)nativeGetFileMetadataNode}, + {"nativeGetFileInfoNode", "(JJ)[B", (void*)nativeGetFileInfoNode}, + {"nativeReportStatus", "(JI)Z", (void*)nativeReportStatus}, + {"nativeOnFileCreated", "(IJ[B)Z", (void*)nativeOnFileCreated}, +}; + +} // namespace + +int register_android_service_incremental_IncrementalDataLoaderService(JNIEnv* env) { + return jniRegisterNativeMethods(env, + "android/service/incremental/IncrementalDataLoaderService", + dlc_method_table, NELEM(dlc_method_table)); +} + +} // namespace android diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index fd6984b830d7..0c21076065d5 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -37,6 +37,8 @@ static const char* kPathWhitelist[] = { "/apex/com.android.ipsec/javalib/ike.jar", "/apex/com.android.media/javalib/updatable-media.jar", "/apex/com.android.sdkext/javalib/framework-sdkext.jar", + "/apex/com.android.telephony/javalib/telephony-common.jar", + "/apex/com.android.telephony/javalib/ims-common.jar", "/dev/null", "/dev/socket/zygote", "/dev/socket/zygote_secondary", diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto index 1ec05fb5e9fc..ecb4193a2c6c 100644 --- a/core/proto/android/service/notification.proto +++ b/core/proto/android/service/notification.proto @@ -264,3 +264,14 @@ message ZenPolicyProto { optional Sender priority_calls = 16; optional Sender priority_messages = 17; } + +// Next Tag: 2 +message PackageRemoteViewInfoProto { + optional string package_name = 1; + // add per-package additional info here (like channels) +} + +// Next Tag: 2 +message NotificationRemoteViewsProto { + repeated PackageRemoteViewInfoProto package_remote_view_info = 1; +}
\ No newline at end of file diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f6e91efd2ad7..8f1114cb505e 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -635,10 +635,9 @@ <protected-broadcast android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY" /> - <!-- NETWORK_SET_TIME / NETWORK_SET_TIMEZONE moved from com.android.phone to system server. - They should ultimately be removed. --> + <!-- NETWORK_SET_TIME moved from com.android.phone to system server. It should ultimately be + removed. --> <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIME" /> - <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIMEZONE" /> <!-- For tether entitlement recheck--> <protected-broadcast diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml index 6807f9af3980..9f296f8f7c08 100644 --- a/core/res/res/layout/chooser_grid.xml +++ b/core/res/res/layout/chooser_grid.xml @@ -29,7 +29,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alwaysShow="true" - android:elevation="1dp" + android:elevation="0dp" android:background="@drawable/bottomsheet_background"> <ImageView @@ -55,16 +55,10 @@ android:layout_centerHorizontal="true"/> </RelativeLayout> - <com.android.internal.widget.RecyclerView + <com.android.internal.widget.ViewPager + android:id="@+id/profile_pager" android:layout_width="match_parent" - android:layout_height="match_parent" - android:layoutManager="com.android.internal.widget.GridLayoutManager" - android:id="@+id/resolver_list" - android:clipToPadding="false" - android:background="?attr/colorBackgroundFloating" - android:scrollbars="none" - android:elevation="1dp" - android:nestedScrollingEnabled="true"/> + android:layout_height="wrap_content"/> <TextView android:id="@+id/empty" android:layout_width="match_parent" diff --git a/core/res/res/layout/chooser_list_per_profile.xml b/core/res/res/layout/chooser_list_per_profile.xml new file mode 100644 index 000000000000..212813f10bd4 --- /dev/null +++ b/core/res/res/layout/chooser_list_per_profile.xml @@ -0,0 +1,27 @@ +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<com.android.internal.widget.RecyclerView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layoutManager="com.android.internal.widget.GridLayoutManager" + android:id="@+id/resolver_list" + android:clipToPadding="false" + android:background="?attr/colorBackgroundFloating" + android:scrollbars="none" + android:elevation="1dp" + android:nestedScrollingEnabled="true"/>
\ No newline at end of file diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml index 6e45e7a4c509..c5d891254227 100644 --- a/core/res/res/layout/resolver_list.xml +++ b/core/res/res/layout/resolver_list.xml @@ -63,25 +63,22 @@ </RelativeLayout> <View + android:id="@+id/divider" android:layout_alwaysShow="true" android:layout_width="match_parent" android:layout_height="1dp" android:background="?attr/colorBackgroundFloating" android:foreground="?attr/dividerVertical" /> - <ListView + + <com.android.internal.app.WrapHeightViewPager + android:id="@+id/profile_pager" android:layout_width="match_parent" android:layout_height="wrap_content" - android:id="@+id/resolver_list" - android:clipToPadding="false" - android:background="?attr/colorBackgroundFloating" - android:elevation="@dimen/resolver_elevation" - android:nestedScrollingEnabled="true" - android:scrollbarStyle="outsideOverlay" - android:scrollIndicators="top|bottom" android:divider="?attr/dividerVertical" android:footerDividersEnabled="false" android:headerDividersEnabled="false" - android:dividerHeight="1dp" /> + android:dividerHeight="1dp"/> + <View android:layout_alwaysShow="true" android:layout_width="match_parent" @@ -89,7 +86,6 @@ android:background="?attr/colorBackgroundFloating" android:foreground="?attr/dividerVertical" /> - <TextView android:id="@+id/empty" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/core/res/res/layout/resolver_list_per_profile.xml b/core/res/res/layout/resolver_list_per_profile.xml new file mode 100644 index 000000000000..68b991755e73 --- /dev/null +++ b/core/res/res/layout/resolver_list_per_profile.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<ListView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/resolver_list" + android:clipToPadding="false" + android:background="?attr/colorBackgroundFloating" + android:elevation="@dimen/resolver_elevation" + android:nestedScrollingEnabled="true" + android:scrollbarStyle="outsideOverlay" + android:scrollIndicators="top|bottom" + android:divider="?attr/dividerVertical" + android:footerDividersEnabled="false" + android:headerDividersEnabled="false" + android:dividerHeight="1dp" />
\ No newline at end of file diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml index dbba0b7bcc25..5b3d929d23a5 100644 --- a/core/res/res/layout/resolver_list_with_default.xml +++ b/core/res/res/layout/resolver_list_with_default.xml @@ -144,25 +144,21 @@ </LinearLayout> <View + android:id="@+id/divider" android:layout_alwaysShow="true" android:layout_width="match_parent" android:layout_height="1dp" android:background="?attr/colorBackgroundFloating" android:foreground="?attr/dividerVertical" /> - <ListView + + <com.android.internal.app.WrapHeightViewPager + android:id="@+id/profile_pager" android:layout_width="match_parent" android:layout_height="wrap_content" - android:id="@+id/resolver_list" - android:clipToPadding="false" - android:background="?attr/colorBackgroundFloating" - android:elevation="@dimen/resolver_elevation" - android:nestedScrollingEnabled="true" - android:scrollbarStyle="outsideOverlay" - android:scrollIndicators="top|bottom" + android:dividerHeight="1dp" android:divider="?attr/dividerVertical" android:footerDividersEnabled="false" - android:headerDividersEnabled="false" - android:dividerHeight="1dp" /> + android:headerDividersEnabled="false"/> <View android:layout_alwaysShow="true" android:layout_width="match_parent" diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml index 655d4dde5e57..3ecb1dddd916 100644 --- a/core/res/res/values-television/config.xml +++ b/core/res/res/values-television/config.xml @@ -42,8 +42,4 @@ <!-- Allow SystemUI to show the shutdown dialog --> <bool name="config_showSysuiShutdown">true</bool> - - <!-- The time in milliseconds of prolonged user inactivity after which device goes to sleep, - even if wakelocks are held. On TVs, this defaults to 4 hours. --> - <integer name="config_attentiveTimeout">14400000</integer> </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 10a75842d7c6..ced5deb66899 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2851,9 +2851,6 @@ <!-- String array containing numbers that shouldn't be logged. Country-specific. --> <string-array name="unloggable_phone_numbers" /> - <!-- Flag specifying whether or not IMS will use the dynamic ImsResolver --> - <bool name="config_dynamic_bind_ims">false</bool> - <!-- Cellular data service package name to bind to by default. If none is specified in an overlay, an empty string is passed in --> <string name="config_wwan_data_service_package" translatable="false">com.android.phone</string> @@ -3523,8 +3520,9 @@ protection level. Note, framework by default support multiple telephony apps, each package name is separated by comma. Example: "com.android.phone,com.android.stk,com.android.providers.telephony" + (Note: shell is included for testing purposes) --> - <string name="config_telephonyPackages" translatable="false">"com.android.phone,com.android.stk,com.android.providers.telephony,com.android.ons,com.android.cellbroadcastservice"</string> + <string name="config_telephonyPackages" translatable="false">"com.android.phone,com.android.stk,com.android.providers.telephony,com.android.ons,com.android.cellbroadcastservice,com.android.cellbroadcastreceiver,com.android.shell"</string> <!-- The component name for the default system attention service. This service must be trusted, as it can be activated without explicit consent of the user. @@ -4187,4 +4185,18 @@ <!-- The package name for the default bug report handler app from power menu short press. This app must be whitelisted. --> <string name="config_defaultBugReportHandlerApp" translatable="false"></string> + + <!-- The default value used for RawContacts.ACCOUNT_NAME when contacts are inserted without this + column set. These contacts are stored locally on the device and will not be removed even + if an android.account.Account with this name and type exists. A null string will be used + if the value is left empty. When this is non-empty then config_rawContactsLocalAccountType + should also be non-empty. --> + <string name="config_rawContactsLocalAccountName" translatable="false"></string> + + <!-- The default value used for RawContacts.ACCOUNT_TYPE when contacts are inserted without this + column set. These contacts are stored locally on the device and will not be removed even + if an android.account.Account with this name and type exists. A null string will be used + if the value is left empty. When this is non-empty then config_rawContactsLocalAccountName + should also be non-empty.--> + <string name="config_rawContactsLocalAccountType" translatable="false"></string> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 083f33cc8035..90343e07d4e4 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -247,6 +247,7 @@ <java-symbol type="id" name="mic" /> <java-symbol type="id" name="overlay" /> <java-symbol type="id" name="app_ops" /> + <java-symbol type="id" name="profile_pager" /> <java-symbol type="attr" name="actionModeShareDrawable" /> <java-symbol type="attr" name="alertDialogCenterButtons" /> @@ -294,7 +295,6 @@ <java-symbol type="bool" name="config_hotswapCapable" /> <java-symbol type="bool" name="config_mms_content_disposition_support" /> <java-symbol type="string" name="config_ims_package" /> - <java-symbol type="bool" name="config_dynamic_bind_ims" /> <java-symbol type="string" name="config_wwan_network_service_package" /> <java-symbol type="string" name="config_wlan_network_service_package" /> <java-symbol type="string" name="config_wwan_network_service_class" /> @@ -1534,6 +1534,8 @@ <java-symbol type="layout" name="user_switching_dialog" /> <java-symbol type="layout" name="common_tab_settings" /> <java-symbol type="layout" name="notification_material_media_seekbar" /> + <java-symbol type="layout" name="resolver_list_per_profile" /> + <java-symbol type="layout" name="chooser_list_per_profile" /> <java-symbol type="anim" name="slide_in_child_bottom" /> <java-symbol type="anim" name="slide_in_right" /> @@ -3769,4 +3771,8 @@ <java-symbol type="string" name="accessibility_system_action_toggle_split_screen_label" /> <java-symbol type="string" name="accessibility_freeform_caption" /> + + <!-- For contacts provider. --> + <java-symbol type="string" name="config_rawContactsLocalAccountName" /> + <java-symbol type="string" name="config_rawContactsLocalAccountType" /> </resources> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index 0c52029b93f8..cef21db1e0f8 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -1735,6 +1735,7 @@ easier. <item name="colorBackground">@color/background_device_default_light</item> <item name="colorBackgroundFloating">@color/background_device_default_light</item> <item name="layout_gravity">center</item> + <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item> </style> <style name="Theme.DeviceDefault.Notification" parent="@style/Theme.Material.Notification"> diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index a4c504b9cbdf..c009f588f8a9 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -74,7 +74,6 @@ java_genrule { ":FrameworksCoreTests_install_loc_internal", ":FrameworksCoreTests_install_loc_sdcard", ":FrameworksCoreTests_install_loc_unspecified", - ":FrameworksCoreTests_install_multi_package", ":FrameworksCoreTests_install_split_base", ":FrameworksCoreTests_install_split_feature_a", ":FrameworksCoreTests_install_use_perm_good", diff --git a/core/tests/coretests/apks/install_multi_package/Android.bp b/core/tests/coretests/apks/install_multi_package/Android.bp deleted file mode 100644 index 249242e239e4..000000000000 --- a/core/tests/coretests/apks/install_multi_package/Android.bp +++ /dev/null @@ -1,6 +0,0 @@ -android_test_helper_app { - name: "FrameworksCoreTests_install_multi_package", - defaults: ["FrameworksCoreTests_apks_defaults"], - - srcs: ["**/*.java"], -} diff --git a/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml b/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml deleted file mode 100644 index 5164cae9e5c0..000000000000 --- a/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml +++ /dev/null @@ -1,104 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<manifest - xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.coretests.install_multi_package"> - -<!-- - This manifest is has child packages with components. ---> - - <uses-feature - android:name="com.android.frameworks.coretests.nonexistent" /> - <uses-configuration - android:reqFiveWayNav="false" /> - - <instrumentation - android:name="android.test.InstrumentationTestRunner" - android:targetPackage="com.android.frameworks.coretests" - android:label="Frameworks Core Tests" /> - - <permission - android:label="test permission" - android:name="test_permission" - android:protectionLevel="normal" /> - <uses-permission android:name="android.permission.INTERNET" /> - -<!-- - NOTE: This declares a child package, application, then another child - package, to test potential bugs that are order-dependent. Also, each - one varies the order. ---> - - <package package="com.android.frameworks.coretests.install_multi_package.first_child"> - <uses-permission android:name="android.permission.NFC" /> - <!-- NOTE: A declared permission is ignored since the tag is not whitelisted. --> - <permission - android:label="test permission" - android:name="first_child_permission" - android:protectionLevel="signature" /> - <application - android:hasCode="true"> - <activity - android:name="com.android.frameworks.coretests.FirstChildTestActivity"> - </activity> - <provider - android:name="com.android.frameworks.coretests.FirstChildTestProvider" - android:authorities="com.android.frameworks.coretests.testprovider" /> - <receiver - android:name="com.android.frameworks.coretests.FirstChildTestReceiver" /> - <service - android:name="com.android.frameworks.coretests.FirstChildTestService" /> - </application> - </package> - - <application - android:hasCode="true"> - <service - android:name="com.android.frameworks.coretests.TestService" /> - <activity - android:name="com.android.frameworks.coretests.TestActivity"> - </activity> - <provider - android:name="com.android.frameworks.coretests.TestProvider" - android:authorities="com.android.frameworks.coretests.testprovider" /> - <receiver - android:name="com.android.frameworks.coretests.TestReceiver" /> - </application> - - <package package="com.android.frameworks.coretests.blah.second_child"> - <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - <uses-permission-sdk-23 android:name="android.permission.READ_CONTACTS" /> - <!-- NOTE: A declared permission is ignored since the tag is not whitelisted. --> - <permission - android:label="test permission" - android:name="second_child_permission" - android:protectionLevel="dangerous" /> - <application - android:hasCode="true"> - <receiver - android:name="com.android.frameworks.coretests.SecondChildTestReceiver" /> - <service - android:name="com.android.frameworks.coretests.SecondChildTestService" /> - <activity - android:name="com.android.frameworks.coretests.SecondChildTestActivity"> - </activity> - <provider - android:name="com.android.frameworks.coretests.SecondChildTestProvider" - android:authorities="com.android.frameworks.coretests.testprovider" /> - </application> - </package> -</manifest> diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java deleted file mode 100644 index 2816865b2f1f..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 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.frameworks.coretests; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class FirstChildTestProvider extends ContentProvider { - - @Override - public boolean onCreate() { - return false; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java deleted file mode 100644 index ffe84b73dd37..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 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.frameworks.coretests; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class FirstChildTestReceiver extends ContentProvider { - - @Override - public boolean onCreate() { - return false; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java deleted file mode 100644 index e89f26489959..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2011 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.frameworks.coretests; - -import android.app.Activity; - -public class SecondChildTestActivity extends Activity { - -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java deleted file mode 100644 index 2bd40a5df94d..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 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.frameworks.coretests; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class SecondChildTestProvider extends ContentProvider { - - @Override - public boolean onCreate() { - return false; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java deleted file mode 100644 index a6c4ddc90c6a..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 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.frameworks.coretests; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class SecondChildTestReceiver extends ContentProvider { - - @Override - public boolean onCreate() { - return false; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java deleted file mode 100644 index 1e721aa8ae5b..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2011 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.frameworks.coretests; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -public class SecondChildTestService extends Service { - - @Override - public IBinder onBind(Intent intent) { - return null; - } -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java deleted file mode 100644 index 59f9f10c6efe..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 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.frameworks.coretests; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class TestProvider extends ContentProvider { - - @Override - public boolean onCreate() { - return false; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java deleted file mode 100644 index 21f6263a38bc..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 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.frameworks.coretests; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class TestReceiver extends ContentProvider { - - @Override - public boolean onCreate() { - return false; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java deleted file mode 100644 index b330e75308f9..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2011 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.frameworks.coretests; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -public class TestService extends Service { - - @Override - public IBinder onBind(Intent intent) { - return null; - } -} diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java deleted file mode 100644 index cc48239c4526..000000000000 --- a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm; - -import static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE; -import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER; - -import android.os.Build; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Test for {@link AndroidHidlUpdater} - */ -@SmallTest -@RunWith(JUnit4.class) -public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { - - private static final String OTHER_LIBRARY = "other.library"; - - @Test - public void targeted_at_P() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.P); - - // no change, not system - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_P_system() { - PackageBuilder before = builder().asSystemApp() - .targetSdkVersion(Build.VERSION_CODES.P); - - // Should add both HIDL libraries - PackageBuilder after = builder().asSystemApp() - .targetSdkVersion(Build.VERSION_CODES.P) - .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_P_not_empty_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.P) - .requiredLibraries(OTHER_LIBRARY); - - // no change, not system - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_P_not_empty_usesLibraries_system() { - PackageBuilder before = builder().asSystemApp() - .targetSdkVersion(Build.VERSION_CODES.P) - .requiredLibraries(OTHER_LIBRARY); - - // The hidl jars should be added at the start of the list because it - // is not on the bootclasspath and the package targets pre-P. - PackageBuilder after = builder().asSystemApp() - .targetSdkVersion(Build.VERSION_CODES.P) - .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE, OTHER_LIBRARY); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_P_in_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.P) - .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE); - - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.P); - - // Libraries are removed because they are not available for non-system apps - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_P_in_usesLibraries_system() { - PackageBuilder before = builder().asSystemApp() - .targetSdkVersion(Build.VERSION_CODES.P) - .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE); - - // No change is required because the package explicitly requests the HIDL libraries - // and is targeted at the current version so does not need backwards compatibility. - checkBackwardsCompatibility(before, before); - } - - @Test - public void in_usesLibraries() { - PackageBuilder before = builder().requiredLibraries(ANDROID_HIDL_BASE); - - // Dependency is removed, it is not available. - PackageBuilder after = builder(); - - // Libraries are removed because they are not available for apps targetting Q+ - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_usesOptionalLibraries() { - PackageBuilder before = builder().optionalLibraries(ANDROID_HIDL_BASE); - - // Dependency is removed, it is not available. - PackageBuilder after = builder(); - - // Libraries are removed because they are not available for apps targetting Q+ - checkBackwardsCompatibility(before, after); - } - - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { - checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new); - } -} diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java deleted file mode 100644 index 03108ced4816..000000000000 --- a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm; - -import static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE; - -import android.os.Build; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test for {@link AndroidTestBaseUpdater} - */ -@SmallTest -@RunWith(OptionalClassRunner.class) -@OptionalClassRunner.OptionalClass("android.content.pm.AndroidTestBaseUpdater") -public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest { - - private static final String OTHER_LIBRARY = "other.library"; - - @Test - public void targeted_at_Q() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.Q); - - // Should add org.apache.http.legacy. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.Q) - .requiredLibraries(ANDROID_TEST_BASE); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_Q_not_empty_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.Q) - .requiredLibraries(OTHER_LIBRARY); - - // The org.apache.http.legacy jar should be added at the start of the list because it - // is not on the bootclasspath and the package targets pre-Q. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.Q) - .requiredLibraries(ANDROID_TEST_BASE, OTHER_LIBRARY); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_Q_in_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.Q) - .requiredLibraries(ANDROID_TEST_BASE); - - // No change is required because although org.apache.http.legacy has been removed from - // the bootclasspath the package explicitly requests it. - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_Q_in_usesOptionalLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.Q) - .optionalLibraries(ANDROID_TEST_BASE); - - // No change is required because although org.apache.http.legacy has been removed from - // the bootclasspath the package explicitly requests it. - checkBackwardsCompatibility(before, before); - } - - @Test - public void in_usesLibraries() { - PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_BASE); - - // No change is required because the package explicitly requests org.apache.http.legacy - // and is targeted at the current version so does not need backwards compatibility. - checkBackwardsCompatibility(before, before); - } - - @Test - public void in_usesOptionalLibraries() { - PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_BASE); - - // No change is required because the package explicitly requests org.apache.http.legacy - // and is targeted at the current version so does not need backwards compatibility. - checkBackwardsCompatibility(before, before); - } - - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { - checkBackwardsCompatibility(before, after, AndroidTestBaseUpdater::new); - } -} diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java deleted file mode 100644 index 7f817d66caf7..000000000000 --- a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm; - -import static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER; - -import android.content.pm.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Test for {@link AndroidTestRunnerSplitUpdater} - */ -@SmallTest -@RunWith(JUnit4.class) -public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdaterTest { - - @Test - public void android_test_runner_in_usesOptionalLibraries() { - PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_RUNNER); - - PackageBuilder after = builder() - .optionalLibraries(ANDROID_TEST_MOCK, ANDROID_TEST_RUNNER); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() { - PackageBuilder before = builder() - .requiredLibraries(ANDROID_TEST_RUNNER) - .optionalLibraries(ANDROID_TEST_MOCK); - - PackageBuilder after = builder() - .requiredLibraries(ANDROID_TEST_RUNNER) - .optionalLibraries(ANDROID_TEST_MOCK); - - checkBackwardsCompatibility(before, after); - } - - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { - checkBackwardsCompatibility(before, after, AndroidTestRunnerSplitUpdater::new); - } -} diff --git a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java deleted file mode 100644 index 834a0bbeab89..000000000000 --- a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm; - -import static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; - -import android.os.Build; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test for {@link OrgApacheHttpLegacyUpdater} - */ -@SmallTest -@RunWith(OptionalClassRunner.class) -@OptionalClassRunner.OptionalClass("android.content.pm.OrgApacheHttpLegacyUpdater") -public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterTest { - - private static final String OTHER_LIBRARY = "other.library"; - - @Test - public void targeted_at_O() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - // Should add org.apache.http.legacy. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(ORG_APACHE_HTTP_LEGACY); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_O_not_empty_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(OTHER_LIBRARY); - - // The org.apache.http.legacy jar should be added at the start of the list because it - // is not on the bootclasspath and the package targets pre-P. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(ORG_APACHE_HTTP_LEGACY, OTHER_LIBRARY); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_O_in_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(ORG_APACHE_HTTP_LEGACY); - - // No change is required because although org.apache.http.legacy has been removed from - // the bootclasspath the package explicitly requests it. - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_O_in_usesOptionalLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .optionalLibraries(ORG_APACHE_HTTP_LEGACY); - - // No change is required because although org.apache.http.legacy has been removed from - // the bootclasspath the package explicitly requests it. - checkBackwardsCompatibility(before, before); - } - - @Test - public void in_usesLibraries() { - PackageBuilder before = builder().requiredLibraries(ORG_APACHE_HTTP_LEGACY); - - // No change is required because the package explicitly requests org.apache.http.legacy - // and is targeted at the current version so does not need backwards compatibility. - checkBackwardsCompatibility(before, before); - } - - @Test - public void in_usesOptionalLibraries() { - PackageBuilder before = builder().optionalLibraries(ORG_APACHE_HTTP_LEGACY); - - // No change is required because the package explicitly requests org.apache.http.legacy - // and is targeted at the current version so does not need backwards compatibility. - checkBackwardsCompatibility(before, before); - } - - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { - checkBackwardsCompatibility(before, after, OrgApacheHttpLegacyUpdater::new); - } -} diff --git a/core/tests/coretests/src/android/content/pm/PackageBuilder.java b/core/tests/coretests/src/android/content/pm/PackageBuilder.java deleted file mode 100644 index f7544af43461..000000000000 --- a/core/tests/coretests/src/android/content/pm/PackageBuilder.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm; - -import static org.junit.Assert.assertEquals; - -import android.os.Build; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Test support for building {@link PackageParser.Package} instances. - */ -class PackageBuilder { - - private int mTargetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - - private int mFlags = 0; - - private ArrayList<String> mRequiredLibraries; - - private ArrayList<String> mOptionalLibraries; - - public static PackageBuilder builder() { - return new PackageBuilder(); - } - - public PackageParser.Package build() { - PackageParser.Package pkg = new PackageParser.Package("org.package.name"); - pkg.applicationInfo.targetSdkVersion = mTargetSdkVersion; - pkg.applicationInfo.flags = mFlags; - pkg.usesLibraries = mRequiredLibraries; - pkg.usesOptionalLibraries = mOptionalLibraries; - return pkg; - } - - PackageBuilder targetSdkVersion(int version) { - this.mTargetSdkVersion = version; - return this; - } - - PackageBuilder asSystemApp() { - this.mFlags |= ApplicationInfo.FLAG_SYSTEM; - return this; - } - - PackageBuilder requiredLibraries(String... names) { - this.mRequiredLibraries = arrayListOrNull(names); - return this; - } - - PackageBuilder requiredLibraries(List<String> names) { - this.mRequiredLibraries = arrayListOrNull(names.toArray(new String[names.size()])); - return this; - } - - PackageBuilder optionalLibraries(String... names) { - this.mOptionalLibraries = arrayListOrNull(names); - return this; - } - - /** - * Check that this matches the supplied {@link PackageParser.Package}. - * - * @param pkg the instance to compare with this. - */ - public void check(PackageParser.Package pkg) { - assertEquals("targetSdkVersion should not be changed", - mTargetSdkVersion, - pkg.applicationInfo.targetSdkVersion); - assertEquals("usesLibraries not updated correctly", - mRequiredLibraries, - pkg.usesLibraries); - assertEquals("usesOptionalLibraries not updated correctly", - mOptionalLibraries, - pkg.usesOptionalLibraries); - } - - private static ArrayList<String> arrayListOrNull(String... strings) { - if (strings == null || strings.length == 0) { - return null; - } - ArrayList<String> list = new ArrayList<>(); - Collections.addAll(list, strings); - return list; - } - -} diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java index 5c7f2af782b9..440219018b92 100644 --- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java +++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java @@ -23,26 +23,26 @@ import static org.junit.Assert.assertTrue; import android.apex.ApexInfo; import android.content.Context; -import android.content.pm.PackageParser.Component; -import android.content.pm.PackageParser.Package; -import android.content.pm.PackageParser.Permission; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ParsedPackage; import android.os.Build; import android.os.Bundle; import android.os.FileUtils; -import android.os.SystemProperties; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.coretests.R; +import com.android.internal.util.ArrayUtils; import org.junit.Test; import org.junit.runner.RunWith; import java.io.File; import java.io.InputStream; -import java.util.Arrays; import java.util.function.Function; @SmallTest @@ -59,8 +59,8 @@ public class PackageParserTest { private static final String PRE_RELEASE_WITH_FINGERPRINT = "B.fingerprint"; private static final String NEWER_PRE_RELEASE_WITH_FINGERPRINT = "C.fingerprint"; - private static final String[] CODENAMES_RELEASED = { /* empty */ }; - private static final String[] CODENAMES_PRE_RELEASE = { PRE_RELEASE }; + private static final String[] CODENAMES_RELEASED = { /* empty */}; + private static final String[] CODENAMES_PRE_RELEASE = {PRE_RELEASE}; private static final int OLDER_VERSION = 10; private static final int PLATFORM_VERSION = 20; @@ -300,10 +300,6 @@ public class PackageParserTest { assertEquals(0x0083, finalConfigChanges); // Should be 10000011. } - Package parsePackage(String apkFileName, int apkResourceId) throws Exception { - return parsePackage(apkFileName, apkResourceId, p -> p); - } - /** * Copies a specified {@code resourceId} to a file. Returns a non-null file if the copy * succeeded, or {@code null} otherwise. @@ -331,16 +327,17 @@ public class PackageParserTest { * * APKs are put into coretests/apks/packageparser_*. * - * @param apkFileName temporary file name to store apk extracted from resources + * @param apkFileName temporary file name to store apk extracted from resources * @param apkResourceId identifier of the apk as a resource */ - Package parsePackage(String apkFileName, int apkResourceId, - Function<Package, Package> converter) throws Exception { + ParsedPackage parsePackage(String apkFileName, int apkResourceId, + Function<ParsedPackage, ParsedPackage> converter) throws Exception { // Copy the resource to a file. File outFile = null; try { outFile = copyRawResourceToFile(apkFileName, apkResourceId); - return converter.apply(new PackageParser().parsePackage(outFile, 0 /* flags */)); + return converter.apply( + new PackageParser().parseParsedPackage(outFile, 0 /* flags */, false)); } finally { if (outFile != null) { outFile.delete(); @@ -351,40 +348,35 @@ public class PackageParserTest { /** * Asserts basic properties about a component. */ - private void assertComponent(String className, String packageName, int numIntents, - Component<?> component) { + private void assertComponent(String className, int numIntents, ParsedComponent<?> component) { assertEquals(className, component.className); - assertEquals(packageName, component.owner.packageName); assertEquals(numIntents, component.intents.size()); } /** * Asserts four regularly-named components of each type: one Activity, one Service, one * Provider, and one Receiver. + * * @param template templated string with %s subbed with Activity, Service, Provider, Receiver */ - private void assertOneComponentOfEachType(String template, Package p) { - String packageName = p.packageName; - - assertEquals(1, p.activities.size()); + private void assertOneComponentOfEachType(String template, AndroidPackage p) { + assertEquals(1, p.getActivities().size()); assertComponent(String.format(template, "Activity"), - packageName, 0 /* intents */, p.activities.get(0)); - assertEquals(1, p.services.size()); + 0 /* intents */, p.getActivities().get(0)); + assertEquals(1, p.getServices().size()); assertComponent(String.format(template, "Service"), - packageName, 0 /* intents */, p.services.get(0)); - assertEquals(1, p.providers.size()); + 0 /* intents */, p.getServices().get(0)); + assertEquals(1, p.getProviders().size()); assertComponent(String.format(template, "Provider"), - packageName, 0 /* intents */, p.providers.get(0)); - assertEquals(1, p.receivers.size()); + 0 /* intents */, p.getProviders().get(0)); + assertEquals(1, p.getReceivers().size()); assertComponent(String.format(template, "Receiver"), - packageName, 0 /* intents */, p.receivers.get(0)); + 0 /* intents */, p.getReceivers().get(0)); } - private void assertPermission(String name, String packageName, int protectionLevel, - Permission permission) { - assertEquals(packageName, permission.owner.packageName); - assertEquals(name, permission.info.name); - assertEquals(protectionLevel, permission.info.protectionLevel); + private void assertPermission(String name, int protectionLevel, ParsedPermission permission) { + assertEquals(name, permission.getName()); + assertEquals(protectionLevel, permission.getProtection()); } private void assertMetadata(Bundle b, String... keysAndValues) { @@ -416,25 +408,25 @@ public class PackageParserTest { } private void checkPackageWithComponents( - Function<Package, Package> converter) throws Exception { - Package p = parsePackage( + Function<ParsedPackage, ParsedPackage> converter) throws Exception { + ParsedPackage p = parsePackage( "install_complete_package_info.apk", R.raw.install_complete_package_info, converter); String packageName = "com.android.frameworks.coretests.install_complete_package_info"; - assertEquals(packageName, p.packageName); - assertEquals(1, p.permissions.size()); + assertEquals(packageName, p.getPackageName()); + assertEquals(1, p.getPermissions().size()); assertPermission( "com.android.frameworks.coretests.install_complete_package_info.test_permission", - packageName, PermissionInfo.PROTECTION_NORMAL, p.permissions.get(0)); + PermissionInfo.PROTECTION_NORMAL, p.getPermissions().get(0)); // Hidden "app details" activity is added to every package. boolean foundAppDetailsActivity = false; - for (int i = 0; i < p.activities.size(); i++) { - if (p.activities.get(i).className.equals( + for (int i = 0; i < ArrayUtils.size(p.getActivities()); i++) { + if (p.getActivities().get(i).className.equals( PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME)) { foundAppDetailsActivity = true; - p.activities.remove(i); + p.getActivities().remove(i); break; } } @@ -442,72 +434,23 @@ public class PackageParserTest { assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", p); - assertMetadata(p.mAppMetaData, + assertMetadata(p.getAppMetaData(), "key1", "value1", "key2", "this_is_app"); - assertMetadata(p.activities.get(0).metaData, + assertMetadata(p.getActivities().get(0).getMetaData(), "key1", "value1", "key2", "this_is_activity"); - assertMetadata(p.services.get(0).metaData, + assertMetadata(p.getServices().get(0).getMetaData(), "key1", "value1", "key2", "this_is_service"); - assertMetadata(p.receivers.get(0).metaData, + assertMetadata(p.getReceivers().get(0).getMetaData(), "key1", "value1", "key2", "this_is_receiver"); - assertMetadata(p.providers.get(0).metaData, + assertMetadata(p.getProviders().get(0).getMetaData(), "key1", "value1", "key2", "this_is_provider"); } - /** - * Determines if the current device supports multi-package APKs. - */ - private boolean supportsMultiPackageApk() { - return SystemProperties.getBoolean("persist.sys.child_packages_enabled", false); - } - - @Test - public void testMultiPackageComponents() throws Exception { - // TODO(gboyer): Remove once we decide to launch multi-package APKs. - if (!supportsMultiPackageApk()) { - return; - } - String parentName = "com.android.frameworks.coretests.install_multi_package"; - String firstChildName = - "com.android.frameworks.coretests.install_multi_package.first_child"; - String secondChildName = // NOTE: intentionally inconsistent! - "com.android.frameworks.coretests.blah.second_child"; - - Package parent = parsePackage("install_multi_package.apk", R.raw.install_multi_package); - assertEquals(parentName, parent.packageName); - assertEquals(2, parent.childPackages.size()); - assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", parent); - assertEquals(1, parent.permissions.size()); - assertPermission(parentName + ".test_permission", parentName, - PermissionInfo.PROTECTION_NORMAL, parent.permissions.get(0)); - assertEquals(Arrays.asList("android.permission.INTERNET"), - parent.requestedPermissions); - - Package firstChild = parent.childPackages.get(0); - assertEquals(firstChildName, firstChild.packageName); - assertOneComponentOfEachType( - "com.android.frameworks.coretests.FirstChildTest%s", firstChild); - assertEquals(0, firstChild.permissions.size()); // Child APKs cannot declare permissions. - assertEquals(Arrays.asList("android.permission.NFC"), - firstChild.requestedPermissions); - - Package secondChild = parent.childPackages.get(1); - assertEquals(secondChildName, secondChild.packageName); - assertOneComponentOfEachType( - "com.android.frameworks.coretests.SecondChildTest%s", secondChild); - assertEquals(0, secondChild.permissions.size()); // Child APKs cannot declare permissions. - assertEquals( - Arrays.asList( - "android.permission.ACCESS_NETWORK_STATE", - "android.permission.READ_CONTACTS"), - secondChild.requestedPermissions); - } - @Test public void testApexPackageInfoGeneration() throws Exception { String apexModuleName = "com.android.tzdata.apex"; @@ -522,7 +465,7 @@ public class PackageParserTest { int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES; PackageParser pp = new PackageParser(); - Package p = pp.parsePackage(apexFile, flags, false); + PackageParser.Package p = pp.parsePackage(apexFile, flags, false); PackageParser.collectCertificates(p, false); PackageInfo pi = PackageParser.generatePackageInfo(p, apexInfo, flags); diff --git a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java b/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java deleted file mode 100644 index 71a0e5e51b71..000000000000 --- a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm; - -import java.util.function.Supplier; - -/** - * Helper for classes that test {@link PackageSharedLibraryUpdater}. - */ -abstract class PackageSharedLibraryUpdaterTest { - - static void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after, - Supplier<PackageSharedLibraryUpdater> updaterSupplier) { - PackageParser.Package pkg = before.build(); - updaterSupplier.get().updatePackage(pkg); - after.check(pkg); - } -} diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java deleted file mode 100644 index 216b0c8950b7..000000000000 --- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm; - -import static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE; - -import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; -import android.os.Build; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary} - */ -@SmallTest -@RunWith(JUnit4.class) -public class RemoveUnnecessaryAndroidTestBaseLibraryTest - extends PackageSharedLibraryUpdaterTest { - - private static final String OTHER_LIBRARY = "other.library"; - - @Test - public void targeted_at_O() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - // No change required. - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_O_not_empty_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(OTHER_LIBRARY); - - // No change required. - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_O_in_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(ANDROID_TEST_BASE); - - // android.test.base should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_O_in_usesOptionalLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .optionalLibraries(ANDROID_TEST_BASE); - - // android.test.base should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_usesLibraries() { - PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_BASE); - - // android.test.base should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_usesOptionalLibraries() { - PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_BASE); - - // android.test.base should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_bothLibraries() { - PackageBuilder before = builder() - .requiredLibraries(ANDROID_TEST_BASE) - .optionalLibraries(ANDROID_TEST_BASE); - - // android.test.base should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); - - checkBackwardsCompatibility(before, after); - } - - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { - // TODO(b/72538146) - Cannot use constructor reference here because it is also used in - // PackageBackwardCompatibility and that seems to create a package-private lambda in - // android.content.pm which this then tries to reuse but fails because it cannot access - // package-private classes/members because the test is loaded by a different ClassLoader - // than the lambda. - checkBackwardsCompatibility(before, after, - () -> new RemoveUnnecessaryAndroidTestBaseLibrary()); - } - -} diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java deleted file mode 100644 index fc60980bb796..000000000000 --- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm; - -import static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; - -import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary; -import android.os.Build; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary} - */ -@SmallTest -@RunWith(JUnit4.class) -public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest - extends PackageSharedLibraryUpdaterTest { - - private static final String OTHER_LIBRARY = "other.library"; - - @Test - public void targeted_at_O() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - // No change required. - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_O_not_empty_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(OTHER_LIBRARY); - - // No change required. - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_O_in_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(ORG_APACHE_HTTP_LEGACY); - - // org.apache.http.legacy should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_O_in_usesOptionalLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .optionalLibraries(ORG_APACHE_HTTP_LEGACY); - - // org.apache.http.legacy should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_usesLibraries() { - PackageBuilder before = builder().requiredLibraries(ORG_APACHE_HTTP_LEGACY); - - // org.apache.http.legacy should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_usesOptionalLibraries() { - PackageBuilder before = builder().optionalLibraries(ORG_APACHE_HTTP_LEGACY); - - // org.apache.http.legacy should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_bothLibraries() { - PackageBuilder before = builder() - .requiredLibraries(ORG_APACHE_HTTP_LEGACY) - .optionalLibraries(ORG_APACHE_HTTP_LEGACY); - - // org.apache.http.legacy should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); - - checkBackwardsCompatibility(before, after); - } - - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { - // TODO(b/72538146) - Cannot use constructor reference here because it is also used in - // PackageBackwardCompatibility and that seems to create a package-private lambda in - // android.content.pm which this then tries to reuse but fails because it cannot access - // package-private classes/members because the test is loaded by a different ClassLoader - // than the lambda. - checkBackwardsCompatibility(before, after, - () -> new RemoveUnnecessaryOrgApacheHttpLegacyLibrary()); - } -} diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java index 49849ee72a18..1e0bfb08693f 100644 --- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java +++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java @@ -25,9 +25,9 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.ApkLite; -import android.content.pm.PackageParser.Package; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.parsing.ParsedPackage; import android.os.FileUtils; import androidx.test.InstrumentationRegistry; @@ -36,7 +36,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.coretests.R; -import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -95,13 +94,13 @@ public class DexMetadataHelperTest { public void testParsePackageWithDmFileValid() throws IOException, PackageParserException { copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); createDexMetadataFile("install_split_base.apk"); - Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false); Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg); assertEquals(1, packageDexMetadata.size()); - String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath); + String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath()); assertNotNull(baseDexMetadata); - assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath)); + assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath())); } @Test @@ -111,17 +110,17 @@ public class DexMetadataHelperTest { copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a); createDexMetadataFile("install_split_base.apk"); createDexMetadataFile("install_split_feature_a.apk"); - Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false); Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg); assertEquals(2, packageDexMetadata.size()); - String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath); + String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath()); assertNotNull(baseDexMetadata); - assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath)); + assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath())); - String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]); + String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]); assertNotNull(splitDexMetadata); - assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0])); + assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.getSplitCodePaths()[0])); } @Test @@ -130,14 +129,14 @@ public class DexMetadataHelperTest { copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a); createDexMetadataFile("install_split_feature_a.apk"); - Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false); Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg); assertEquals(1, packageDexMetadata.size()); - String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]); + String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]); assertNotNull(splitDexMetadata); - assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0])); + assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.getSplitCodePaths()[0])); } @Test @@ -146,7 +145,8 @@ public class DexMetadataHelperTest { File invalidDmFile = new File(mTmpDir, "install_split_base.dm"); Files.createFile(invalidDmFile.toPath()); try { - PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + ParsedPackage pkg = new PackageParser() + .parseParsedPackage(mTmpDir, 0 /* flags */, false); DexMetadataHelper.validatePackageDexMetadata(pkg); } catch (PackageParserException e) { assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA); @@ -163,7 +163,8 @@ public class DexMetadataHelperTest { Files.createFile(invalidDmFile.toPath()); try { - PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + ParsedPackage pkg = new PackageParser() + .parseParsedPackage(mTmpDir, 0 /* flags */, false); DexMetadataHelper.validatePackageDexMetadata(pkg); } catch (PackageParserException e) { assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA); diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java new file mode 100644 index 000000000000..21479c096752 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.library; + +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER; + +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Test for {@link AndroidHidlUpdater} + */ +@SmallTest +@RunWith(JUnit4.class) +public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { + + private static final String OTHER_LIBRARY = "other.library"; + + @Test + public void targeted_at_P() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .hideAsParsed() + .hideAsFinal(); + + // no change, not system + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_P_system() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .hideAsParsed() + .setSystem(true); + + // Should add both HIDL libraries + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(ANDROID_HIDL_MANAGER) + .addUsesLibrary(ANDROID_HIDL_BASE) + .hideAsParsed() + .setSystem(true) + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_P_not_empty_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .hideAsFinal(); + + // no change, not system + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_P_not_empty_usesLibraries_system() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .setSystem(true); + + // The hidl jars should be added at the start of the list because it + // is not on the bootclasspath and the package targets pre-P. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(ANDROID_HIDL_MANAGER) + .addUsesLibrary(ANDROID_HIDL_BASE) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .setSystem(true) + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_P_in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(ANDROID_HIDL_MANAGER) + .addUsesLibrary(ANDROID_HIDL_BASE) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .hideAsParsed() + .hideAsFinal(); + + // Libraries are removed because they are not available for non-system apps + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_P_in_usesLibraries_system() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(ANDROID_HIDL_MANAGER) + .addUsesLibrary(ANDROID_HIDL_BASE) + .hideAsParsed() + .setSystem(true); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(ANDROID_HIDL_MANAGER) + .addUsesLibrary(ANDROID_HIDL_BASE) + .hideAsParsed() + .setSystem(true) + .hideAsFinal(); + + // No change is required because the package explicitly requests the HIDL libraries + // and is targeted at the current version so does not need backwards compatibility. + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_HIDL_BASE) + .hideAsParsed(); + + // Dependency is removed, it is not available. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); + + // Libraries are removed because they are not available for apps targeting Q+ + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ANDROID_HIDL_BASE) + .hideAsParsed(); + + // Dependency is removed, it is not available. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); + + // Libraries are removed because they are not available for apps targeting Q+ + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new); + } +} diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java new file mode 100644 index 000000000000..65ae219058f4 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.library; + +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; + +import android.content.pm.OptionalClassRunner; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Test for {@link AndroidTestBaseUpdater} + */ +@SmallTest +@RunWith(OptionalClassRunner.class) +@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.AndroidTestBaseUpdater") +public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest { + + private static final String OTHER_LIBRARY = "other.library"; + + @Test + public void targeted_at_Q() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .hideAsParsed(); + + // Should add org.apache.http.legacy. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_Q_not_empty_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed(); + + // The org.apache.http.legacy jar should be added at the start of the list because it + // is not on the bootclasspath and the package targets pre-Q. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary(ANDROID_TEST_BASE) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_Q_in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because although org.apache.http.legacy has been removed from + // the bootclasspath the package explicitly requests it. + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_Q_in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because although org.apache.http.legacy has been removed from + // the bootclasspath the package explicitly requests it. + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because the package explicitly requests org.apache.http.legacy + // and is targeted at the current version so does not need backwards compatibility. + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because the package explicitly requests org.apache.http.legacy + // and is targeted at the current version so does not need backwards compatibility. + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + checkBackwardsCompatibility(before, after, AndroidTestBaseUpdater::new); + } +} diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java new file mode 100644 index 000000000000..38755b9aa965 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.library; + +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; + +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Test for {@link AndroidTestRunnerSplitUpdater} + */ +@SmallTest +@RunWith(JUnit4.class) +public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdaterTest { + + @Test + public void android_test_runner_in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ANDROID_TEST_RUNNER) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ANDROID_TEST_MOCK) + .addUsesOptionalLibrary(ANDROID_TEST_RUNNER) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_RUNNER) + .addUsesOptionalLibrary(ANDROID_TEST_MOCK) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_RUNNER) + .addUsesOptionalLibrary(ANDROID_TEST_MOCK) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + checkBackwardsCompatibility(before, after, AndroidTestRunnerSplitUpdater::new); + } +} diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java new file mode 100644 index 000000000000..4c7899b47164 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.library; + +import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; + +import android.content.pm.OptionalClassRunner; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Test for {@link OrgApacheHttpLegacyUpdater} + */ +@SmallTest +@RunWith(OptionalClassRunner.class) +@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.OrgApacheHttpLegacyUpdater") +public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterTest { + + private static final String OTHER_LIBRARY = "other.library"; + + @Test + public void targeted_at_O() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed(); + + // Should add org.apache.http.legacy. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_not_empty_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed(); + + // The org.apache.http.legacy jar should be added at the start of the list because it + // is not on the bootclasspath and the package targets pre-P. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because although org.apache.http.legacy has been removed from + // the bootclasspath the package explicitly requests it. + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because although org.apache.http.legacy has been removed from + // the bootclasspath the package explicitly requests it. + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because the package explicitly requests org.apache.http.legacy + // and is targeted at the current version so does not need backwards compatibility. + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because the package explicitly requests org.apache.http.legacy + // and is targeted at the current version so does not need backwards compatibility. + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + checkBackwardsCompatibility(before, after, OrgApacheHttpLegacyUpdater::new); + } +} diff --git a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java index ad9814bd01b1..00d468de4ee4 100644 --- a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java +++ b/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,15 +14,18 @@ * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; -import static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER; -import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; +import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; -import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; import android.os.Build; import androidx.test.filters.SmallTest; @@ -32,17 +35,20 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import java.util.ArrayList; -import java.util.List; - @SmallTest @RunWith(JUnit4.class) public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdaterTest { @Test public void null_usesLibraries_and_usesOptionalLibraries() { - PackageBuilder before = builder(); - PackageBuilder after = builder(); + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); checkBackwardsCompatibility(before, after); } @@ -68,20 +74,21 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate */ @Test public void targeted_at_O() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O); + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed(); + + ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .setTargetSdkVersion(Build.VERSION_CODES.O); - List<String> expected = new ArrayList<>(); if (!PackageBackwardCompatibility.bootClassPathContainsATB()) { - expected.add(ANDROID_TEST_BASE); + after.addUsesLibrary(ANDROID_TEST_BASE); } - expected.add(ORG_APACHE_HTTP_LEGACY); - - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(expected); + after.addUsesLibrary(ORG_APACHE_HTTP_LEGACY); - checkBackwardsCompatibility(before, after); + checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal()); } /** @@ -98,12 +105,17 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate + ANDROID_TEST_BASE + " is on the bootclasspath", PackageBackwardCompatibility.bootClassPathContainsATB()); - PackageBuilder before = builder() - .requiredLibraries(ANDROID_TEST_BASE); + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); // android.test.base should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); checkBackwardsCompatibility(before, after); } @@ -117,22 +129,23 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate */ @Test public void android_test_runner_in_usesLibraries() { - PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_RUNNER); + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_RUNNER) + .hideAsParsed(); - List<String> expected = new ArrayList<>(); + ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT); if (!PackageBackwardCompatibility.bootClassPathContainsATB()) { - expected.add(ANDROID_TEST_BASE); + after.addUsesLibrary(ANDROID_TEST_BASE); } - expected.add(ANDROID_TEST_MOCK); - expected.add(ANDROID_TEST_RUNNER); - - PackageBuilder after = builder() - .requiredLibraries(expected); + after.addUsesLibrary(ANDROID_TEST_MOCK); + after.addUsesLibrary(ANDROID_TEST_RUNNER); - checkBackwardsCompatibility(before, after); + checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal()); } - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance); } } diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java new file mode 100644 index 000000000000..e7a80e1a7618 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.library; + +import static org.junit.Assert.assertEquals; + +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsedPackage; + +import java.util.function.Supplier; + +/** + * Helper for classes that test {@link PackageSharedLibraryUpdater}. + */ +abstract class PackageSharedLibraryUpdaterTest { + + protected static final String PACKAGE_NAME = "org.package.name"; + + static void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after, + Supplier<PackageSharedLibraryUpdater> updaterSupplier) { + updaterSupplier.get().updatePackage(before); + check(before.hideAsFinal(), after); + } + + private static void check(AndroidPackage before, AndroidPackage after) { + assertEquals("targetSdkVersion should not be changed", + after.getTargetSdkVersion(), + before.getTargetSdkVersion()); + assertEquals("usesLibraries not updated correctly", + after.getUsesLibraries(), + before.getUsesLibraries()); + assertEquals("usesOptionalLibraries not updated correctly", + after.getUsesOptionalLibraries(), + before.getUsesOptionalLibraries()); + } +} diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java new file mode 100644 index 000000000000..fd3ba2bd0c68 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.library; + +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; + +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary} + */ +@SmallTest +@RunWith(JUnit4.class) +public class RemoveUnnecessaryAndroidTestBaseLibraryTest + extends PackageSharedLibraryUpdaterTest { + + private static final String OTHER_LIBRARY = "other.library"; + + @Test + public void targeted_at_O() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed() + .hideAsFinal(); + + // No change required. + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_not_empty_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .hideAsFinal(); + + // No change required. + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + // android.test.base should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + // android.test.base should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + // android.test.base should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + // android.test.base should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_bothLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_BASE) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + // android.test.base should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + // TODO(b/72538146) - Cannot use constructor reference here because it is also used in + // PackageBackwardCompatibility and that seems to create a package-private lambda in + // android.content.pm which this then tries to reuse but fails because it cannot access + // package-private classes/members because the test is loaded by a different ClassLoader + // than the lambda. + checkBackwardsCompatibility(before, after, + () -> new RemoveUnnecessaryAndroidTestBaseLibrary()); + } + +} diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java new file mode 100644 index 000000000000..d3494d93ae52 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.parsing.library; + +import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; + +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary} + */ +@SmallTest +@RunWith(JUnit4.class) +public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest + extends PackageSharedLibraryUpdaterTest { + + private static final String OTHER_LIBRARY = "other.library"; + + @Test + public void targeted_at_O() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed() + .hideAsFinal(); + + // No change required. + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_not_empty_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .hideAsFinal(); + + // No change required. + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + // org.apache.http.legacy should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + // org.apache.http.legacy should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + // org.apache.http.legacy should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + // org.apache.http.legacy should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_bothLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + // org.apache.http.legacy should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + // TODO(b/72538146) - Cannot use constructor reference here because it is also used in + // PackageBackwardCompatibility and that seems to create a package-private lambda in + // android.content.pm which this then tries to reuse but fails because it cannot access + // package-private classes/members because the test is loaded by a different ClassLoader + // than the lambda. + checkBackwardsCompatibility(before, after, + () -> new RemoveUnnecessaryOrgApacheHttpLegacyLibrary()); + } +} diff --git a/core/tests/coretests/src/android/util/LocalLogTest.java b/core/tests/coretests/src/android/util/LocalLogTest.java index 6cdcb5e542dc..d4861cd391a8 100644 --- a/core/tests/coretests/src/android/util/LocalLogTest.java +++ b/core/tests/coretests/src/android/util/LocalLogTest.java @@ -29,14 +29,24 @@ import java.util.List; @LargeTest public class LocalLogTest extends TestCase { - public void testA() { + public void testA_localTimestamps() { + boolean localTimestamps = true; + doTestA(localTimestamps); + } + + public void testA_nonLocalTimestamps() { + boolean localTimestamps = false; + doTestA(localTimestamps); + } + + private void doTestA(boolean localTimestamps) { String[] lines = { - "foo", - "bar", - "baz" + "foo", + "bar", + "baz" }; String[] want = lines; - testcase(new LocalLog(10), lines, want); + testcase(new LocalLog(10, localTimestamps), lines, want); } public void testB() { diff --git a/core/tests/coretests/src/android/util/StatsEventTest.java b/core/tests/coretests/src/android/util/StatsEventTest.java index 097badadcea9..ac25e2734ac9 100644 --- a/core/tests/coretests/src/android/util/StatsEventTest.java +++ b/core/tests/coretests/src/android/util/StatsEventTest.java @@ -44,7 +44,7 @@ public class StatsEventTest { @Test public void testNoFields() { final long minTimestamp = SystemClock.elapsedRealtimeNanos(); - final StatsEvent statsEvent = StatsEvent.newBuilder().build(); + final StatsEvent statsEvent = StatsEvent.newBuilder().usePooledBuffer().build(); final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); final int expectedAtomId = 0; @@ -99,6 +99,7 @@ public class StatsEventTest { .writeBoolean(field2) .writeInt(field3) .writeInt(field4) + .usePooledBuffer() .build(); final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); @@ -167,6 +168,7 @@ public class StatsEventTest { .writeString(field1) .writeFloat(field2) .writeByteArray(field3) + .usePooledBuffer() .build(); final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); @@ -230,6 +232,7 @@ public class StatsEventTest { .setAtomId(expectedAtomId) .writeAttributionChain(uids, tags) .writeLong(field2) + .usePooledBuffer() .build(); final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); @@ -299,6 +302,7 @@ public class StatsEventTest { final StatsEvent statsEvent = StatsEvent.newBuilder() .setAtomId(expectedAtomId) .writeKeyValuePairs(intMap, longMap, stringMap, floatMap) + .usePooledBuffer() .build(); final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); @@ -392,6 +396,7 @@ public class StatsEventTest { .addBooleanAnnotation(field1AnnotationId, field1AnnotationValue) .writeBoolean(field2) .addIntAnnotation(field2AnnotationId, field2AnnotationValue) + .usePooledBuffer() .build(); final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java index 7b4054348642..82854e5b8a9d 100644 --- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java +++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java @@ -20,6 +20,7 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHO import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED; import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN; import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -49,8 +50,10 @@ import android.content.DialogInterface; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.media.Ringtone; +import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.Vibrator; @@ -157,9 +160,12 @@ public class AccessibilityShortcutControllerTest { when(mFrameworkObjectProvider.getRingtone(eq(mContext), any())).thenReturn(mRingtone); when(mResources.getString(anyInt())).thenReturn("Howdy %s"); + when(mResources.getString(R.string.config_defaultAccessibilityService)).thenReturn(null); when(mResources.getIntArray(anyInt())).thenReturn(VIBRATOR_PATTERN_INT); ResolveInfo resolveInfo = mock(ResolveInfo.class); + resolveInfo.serviceInfo = mock(ServiceInfo.class); + resolveInfo.serviceInfo.applicationInfo = mApplicationInfo; when(resolveInfo.loadLabel(anyObject())).thenReturn("Service name"); when(mServiceInfo.getResolveInfo()).thenReturn(resolveInfo); when(mServiceInfo.getComponentName()) @@ -200,42 +206,47 @@ public class AccessibilityShortcutControllerTest { } @Test - public void testShortcutAvailable_enabledButNoServiceWhenCreated_shouldReturnFalse() { + public void testShortcutAvailable_enabledButNoServiceWhenCreated_shouldReturnFalse() + throws Exception { configureNoShortcutService(); configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); assertFalse(getController().isAccessibilityShortcutAvailable(false)); } @Test - public void testShortcutAvailable_enabledWithValidServiceWhenCreated_shouldReturnTrue() { + public void testShortcutAvailable_enabledWithValidServiceWhenCreated_shouldReturnTrue() + throws Exception { configureValidShortcutService(); configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); assertTrue(getController().isAccessibilityShortcutAvailable(false)); } @Test - public void testShortcutAvailable_disabledWithValidServiceWhenCreated_shouldReturnFalse() { + public void testShortcutAvailable_disabledWithValidServiceWhenCreated_shouldReturnFalse() + throws Exception { configureValidShortcutService(); configureShortcutEnabled(DISABLED_BUT_LOCK_SCREEN_ON); assertFalse(getController().isAccessibilityShortcutAvailable(false)); } @Test - public void testShortcutAvailable_onLockScreenButDisabledThere_shouldReturnFalse() { + public void testShortcutAvailable_onLockScreenButDisabledThere_shouldReturnFalse() + throws Exception { configureValidShortcutService(); configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); assertFalse(getController().isAccessibilityShortcutAvailable(true)); } @Test - public void testShortcutAvailable_onLockScreenAndEnabledThere_shouldReturnTrue() { + public void testShortcutAvailable_onLockScreenAndEnabledThere_shouldReturnTrue() + throws Exception { configureValidShortcutService(); configureShortcutEnabled(ENABLED_INCLUDING_LOCK_SCREEN); assertTrue(getController().isAccessibilityShortcutAvailable(true)); } @Test - public void testShortcutAvailable_onLockScreenAndLockScreenPreferenceUnset() { + public void testShortcutAvailable_onLockScreenAndLockScreenPreferenceUnset() throws Exception { // When the user hasn't specified a lock screen preference, we allow from the lock screen // as long as the user has agreed to enable the shortcut configureValidShortcutService(); @@ -249,17 +260,19 @@ public class AccessibilityShortcutControllerTest { } @Test - public void testShortcutAvailable_whenServiceIdBecomesNull_shouldReturnFalse() { + public void testShortcutAvailable_whenServiceIdBecomesNull_shouldReturnFalse() + throws Exception { configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); configureValidShortcutService(); AccessibilityShortcutController accessibilityShortcutController = getController(); - Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, ""); + configureNoShortcutService(); accessibilityShortcutController.onSettingsChanged(); assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable(false)); } @Test - public void testShortcutAvailable_whenServiceIdBecomesNonNull_shouldReturnTrue() { + public void testShortcutAvailable_whenServiceIdBecomesNonNull_shouldReturnTrue() + throws Exception { configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); configureNoShortcutService(); AccessibilityShortcutController accessibilityShortcutController = getController(); @@ -269,7 +282,8 @@ public class AccessibilityShortcutControllerTest { } @Test - public void testShortcutAvailable_whenShortcutBecomesDisabled_shouldReturnFalse() { + public void testShortcutAvailable_whenShortcutBecomesDisabled_shouldReturnFalse() + throws Exception { configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); configureValidShortcutService(); AccessibilityShortcutController accessibilityShortcutController = getController(); @@ -279,7 +293,8 @@ public class AccessibilityShortcutControllerTest { } @Test - public void testShortcutAvailable_whenShortcutBecomesEnabled_shouldReturnTrue() { + public void testShortcutAvailable_whenShortcutBecomesEnabled_shouldReturnTrue() + throws Exception { configureShortcutEnabled(DISABLED); configureValidShortcutService(); AccessibilityShortcutController accessibilityShortcutController = getController(); @@ -289,7 +304,8 @@ public class AccessibilityShortcutControllerTest { } @Test - public void testShortcutAvailable_whenLockscreenBecomesDisabled_shouldReturnFalse() { + public void testShortcutAvailable_whenLockscreenBecomesDisabled_shouldReturnFalse() + throws Exception { configureShortcutEnabled(ENABLED_INCLUDING_LOCK_SCREEN); configureValidShortcutService(); AccessibilityShortcutController accessibilityShortcutController = getController(); @@ -299,7 +315,8 @@ public class AccessibilityShortcutControllerTest { } @Test - public void testShortcutAvailable_whenLockscreenBecomesEnabled_shouldReturnTrue() { + public void testShortcutAvailable_whenLockscreenBecomesEnabled_shouldReturnTrue() + throws Exception { configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); configureValidShortcutService(); AccessibilityShortcutController accessibilityShortcutController = getController(); @@ -370,7 +387,7 @@ public class AccessibilityShortcutControllerTest { } @Test - public void testClickingDisableButtonInDialog_shouldClearShortcutId() { + public void testClickingDisableButtonInDialog_shouldClearShortcutId() throws Exception { configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); configureValidShortcutService(); Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0); @@ -458,7 +475,22 @@ public class AccessibilityShortcutControllerTest { } @Test - public void testOnAccessibilityShortcut_showsWarningDialog_shouldTtsSpokenPrompt() { + public void testOnAccessibilityShortcut_sdkGreaterThanQ_reqA11yButton_callsServiceWithNoToast() + throws Exception { + configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); + configureValidShortcutService(); + configureApplicationTargetSdkVersion(Build.VERSION_CODES.R); + configureRequestAccessibilityButton(); + Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1); + getController().performAccessibilityShortcut(); + + verifyZeroInteractions(mToast); + verify(mAccessibilityManagerService).performAccessibilityShortcut(); + } + + @Test + public void testOnAccessibilityShortcut_showsWarningDialog_shouldTtsSpokenPrompt() + throws Exception { configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); configureValidShortcutService(); configureTtsSpokenPromptEnabled(); @@ -482,7 +514,8 @@ public class AccessibilityShortcutControllerTest { } @Test - public void testOnAccessibilityShortcut_showsWarningDialog_ttsInitFail_noSpokenPrompt() { + public void testOnAccessibilityShortcut_showsWarningDialog_ttsInitFail_noSpokenPrompt() + throws Exception { configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); configureValidShortcutService(); configureTtsSpokenPromptEnabled(); @@ -500,19 +533,28 @@ public class AccessibilityShortcutControllerTest { verify(mRingtone).play(); } - private void configureNoShortcutService() { + private void configureNoShortcutService() throws Exception { + when(mAccessibilityManagerService + .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY)) + .thenReturn(Collections.emptyList()); Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, ""); } - private void configureValidShortcutService() { + private void configureValidShortcutService() throws Exception { + when(mAccessibilityManagerService + .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY)) + .thenReturn(Collections.singletonList(SERVICE_NAME_STRING)); Settings.Secure.putString( mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, SERVICE_NAME_STRING); } - private void configureFirstFrameworkFeature() { + private void configureFirstFrameworkFeature() throws Exception { ComponentName featureComponentName = (ComponentName) AccessibilityShortcutController.getFrameworkShortcutFeaturesMap() .keySet().toArray()[0]; + when(mAccessibilityManagerService + .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY)) + .thenReturn(Collections.singletonList(featureComponentName.flattenToString())); Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, featureComponentName.flattenToString()); } @@ -552,6 +594,15 @@ public class AccessibilityShortcutControllerTest { .FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK; } + private void configureRequestAccessibilityButton() { + mServiceInfo.flags |= AccessibilityServiceInfo + .FLAG_REQUEST_ACCESSIBILITY_BUTTON; + } + + private void configureApplicationTargetSdkVersion(int versionCode) { + mApplicationInfo.targetSdkVersion = versionCode; + } + private void configureHandlerCallbackInvocation() { doAnswer((InvocationOnMock invocation) -> { Message m = (Message) invocation.getArguments()[0]; diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index d427cbda7fb6..8622b7efeee7 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -313,7 +313,7 @@ public class ChooserActivityTest { assertThat(activity.isFinishing(), is(false)); onView(withId(R.id.empty)).check(matches(isDisplayed())); - onView(withId(R.id.resolver_list)).check(matches(not(isDisplayed()))); + onView(withId(R.id.profile_pager)).check(matches(not(isDisplayed()))); InstrumentationRegistry.getInstrumentation().runOnMainSync( () -> activity.getAdapter().handlePackagesChanged() ); @@ -674,12 +674,12 @@ public class ChooserActivityTest { mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); waitForIdle(); + // Second invocation is from onCreate verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture()); - // First invocation is from onCreate - assertThat(logMakerCaptor.getAllValues().get(1).getCategory(), - is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)); - assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(), + assertThat(logMakerCaptor.getAllValues().get(0).getSubtype(), is(CONTENT_PREVIEW_TEXT)); + assertThat(logMakerCaptor.getAllValues().get(0).getCategory(), + is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)); } @Test @@ -706,10 +706,10 @@ public class ChooserActivityTest { waitForIdle(); verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture()); // First invocation is from onCreate - assertThat(logMakerCaptor.getAllValues().get(1).getCategory(), - is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)); - assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(), + assertThat(logMakerCaptor.getAllValues().get(0).getSubtype(), is(CONTENT_PREVIEW_IMAGE)); + assertThat(logMakerCaptor.getAllValues().get(0).getCategory(), + is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)); } @Test diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java index 03705d0599e5..a2e0095c2aee 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java @@ -29,6 +29,7 @@ import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; +import android.os.UserHandle; import android.util.Size; import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter; @@ -47,7 +48,7 @@ public class ChooserWrapperActivity extends ChooserActivity { private UsageStatsManager mUsm; ChooserListAdapter getAdapter() { - return (ChooserListAdapter) mAdapter; + return mChooserMultiProfilePagerAdapter.getCurrentListAdapter(); } boolean getIsSelected() { return mIsSuccessfullySelected; } @@ -77,7 +78,7 @@ public class ChooserWrapperActivity extends ChooserActivity { } @Override - protected ResolverListController createListController() { + protected ResolverListController createListController(UserHandle userHandle) { return sOverrides.resolverListController; } diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java index 344c28679568..923ce3e3935d 100644 --- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java @@ -116,14 +116,14 @@ public class ResolverActivityTest { waitForIdle(); final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent); - final View resolverList = activity.findViewById(R.id.resolver_list); - final int initialResolverHeight = resolverList.getHeight(); + final View viewPager = activity.findViewById(R.id.profile_pager); + final int initialResolverHeight = viewPager.getHeight(); activity.runOnUiThread(() -> { ResolverDrawerLayout layout = (ResolverDrawerLayout) activity.findViewById( R.id.contentPanel); - ((ResolverDrawerLayout.LayoutParams) resolverList.getLayoutParams()).maxHeight + ((ResolverDrawerLayout.LayoutParams) viewPager.getLayoutParams()).maxHeight = initialResolverHeight - 1; // Force a relayout layout.invalidate(); @@ -131,13 +131,13 @@ public class ResolverActivityTest { }); waitForIdle(); assertThat("Drawer should be capped at maxHeight", - resolverList.getHeight() == (initialResolverHeight - 1)); + viewPager.getHeight() == (initialResolverHeight - 1)); activity.runOnUiThread(() -> { ResolverDrawerLayout layout = (ResolverDrawerLayout) activity.findViewById( R.id.contentPanel); - ((ResolverDrawerLayout.LayoutParams) resolverList.getLayoutParams()).maxHeight + ((ResolverDrawerLayout.LayoutParams) viewPager.getLayoutParams()).maxHeight = initialResolverHeight + 1; // Force a relayout layout.invalidate(); @@ -145,7 +145,7 @@ public class ResolverActivityTest { }); waitForIdle(); assertThat("Drawer should not change height if its height is less than maxHeight", - resolverList.getHeight() == initialResolverHeight); + viewPager.getHeight() == initialResolverHeight); } @Ignore // Failing - b/144929805 @@ -160,11 +160,13 @@ public class ResolverActivityTest { waitForIdle(); final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent); - final View resolverList = activity.findViewById(R.id.resolver_list); + final View viewPager = activity.findViewById(R.id.profile_pager); + final View divider = activity.findViewById(R.id.divider); final RelativeLayout profileView = (RelativeLayout) activity.findViewById(R.id.profile_button).getParent(); assertThat("Drawer should show at bottom by default", - profileView.getBottom() == resolverList.getTop() && profileView.getTop() > 0); + profileView.getBottom() + divider.getHeight() == viewPager.getTop() + && profileView.getTop() > 0); activity.runOnUiThread(() -> { ResolverDrawerLayout layout = (ResolverDrawerLayout) @@ -174,7 +176,8 @@ public class ResolverActivityTest { }); waitForIdle(); assertThat("Drawer should show at top with new attribute", - profileView.getBottom() == resolverList.getTop() && profileView.getTop() == 0); + profileView.getBottom() + divider.getHeight() == viewPager.getTop() + && profileView.getTop() == 0); } @Test diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java index 5ac1489bcfef..64906bb27ff0 100644 --- a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java @@ -115,7 +115,7 @@ public class ResolverListControllerTest { mUsm = new UsageStatsManager(mMockContext, mMockService); when(mMockContext.getSystemService(Context.USAGE_STATS_SERVICE)).thenReturn(mUsm); mController = new ResolverListController(mMockContext, mMockPackageManager, sendIntent, - refererPackage, UserHandle.USER_CURRENT); + refererPackage, UserHandle.USER_CURRENT, /* userHandle */ UserHandle.SYSTEM); mController.sort(new ArrayList<ResolvedComponentInfo>()); long beforeReport = getCount(mUsm, packageName, action, annotation); mController.updateChooserCounts(packageName, UserHandle.USER_CURRENT, action); @@ -132,7 +132,7 @@ public class ResolverListControllerTest { mUsm = new UsageStatsManager(mMockContext, mMockService); when(mMockContext.getSystemService(Context.USAGE_STATS_SERVICE)).thenReturn(mUsm); mController = new ResolverListController(mMockContext, mMockPackageManager, sendIntent, - refererPackage, UserHandle.USER_CURRENT); + refererPackage, UserHandle.USER_CURRENT, /* userHandle */ UserHandle.SYSTEM); List<ResolvedComponentInfo> topKList = new ArrayList<>(resolvedComponents); mController.topK(topKList, 5); List<ResolvedComponentInfo> sortList = new ArrayList<>(topKList); diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java index 39cc83c3bc43..93357af406e8 100644 --- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java +++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.os.UserHandle; import com.android.internal.app.chooser.TargetInfo; @@ -37,15 +38,15 @@ public class ResolverWrapperActivity extends ResolverActivity { private UsageStatsManager mUsm; @Override - public ResolverListAdapter createAdapter(Context context, List<Intent> payloadIntents, - Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed, - boolean useLayoutForBrowsables) { + public ResolverListAdapter createResolverListAdapter(Context context, + List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, + boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) { return new ResolverWrapperAdapter(context, payloadIntents, initialIntents, rList, - filterLastUsed, createListController(), useLayoutForBrowsables, this); + filterLastUsed, createListController(userHandle), useLayoutForBrowsables, this); } ResolverWrapperAdapter getAdapter() { - return (ResolverWrapperAdapter) mAdapter; + return (ResolverWrapperAdapter) mMultiProfilePagerAdapter.getCurrentListAdapter(); } @Override @@ -66,7 +67,7 @@ public class ResolverWrapperActivity extends ResolverActivity { } @Override - protected ResolverListController createListController() { + protected ResolverListController createListController(UserHandle userHandle) { return sOverrides.resolverListController; } diff --git a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java new file mode 100644 index 000000000000..9002c2c6b184 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.infra; + +import static com.google.common.truth.Truth.assertThat; + +import static org.testng.Assert.expectThrows; + +import android.os.Parcel; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; + +/** + * Unit test for {@link AndroidFuture}. + * + * <p>To run it: + * {@code atest FrameworksCoreTests:com.android.internal.infra.AndroidFutureTest} + */ + +@RunWith(AndroidJUnit4.class) +public class AndroidFutureTest { + @Test + public void testGet() throws Exception { + AndroidFuture<Integer> future = new AndroidFuture<>(); + future.complete(5); + assertThat(future.get()).isEqualTo(5); + } + + @Test + public void testWhenComplete_AlreadyComplete() throws Exception { + AndroidFuture<Integer> future = new AndroidFuture<>(); + future.complete(5); + CountDownLatch latch = new CountDownLatch(1); + future.whenComplete((obj, err) -> { + assertThat(obj).isEqualTo(5); + assertThat(err).isNull(); + latch.countDown(); + }); + latch.await(); + } + + @Test + public void testWhenComplete_NotYetComplete() throws Exception { + AndroidFuture<Integer> future = new AndroidFuture<>(); + CountDownLatch latch = new CountDownLatch(1); + future.whenComplete((obj, err) -> { + assertThat(obj).isEqualTo(5); + assertThat(err).isNull(); + latch.countDown(); + }); + assertThat(latch.getCount()).isEqualTo(1); + future.complete(5); + latch.await(); + assertThat(latch.getCount()).isEqualTo(0); + } + + @Test + public void testCompleteExceptionally() { + AndroidFuture<Integer> future = new AndroidFuture<>(); + Exception origException = new UnsupportedOperationException(); + future.completeExceptionally(origException); + ExecutionException executionException = + expectThrows(ExecutionException.class, future::get); + assertThat(executionException.getCause()).isSameAs(origException); + } + + @Test + public void testCompleteExceptionally_Listener() throws Exception { + AndroidFuture<Integer> future = new AndroidFuture<>(); + Exception origException = new UnsupportedOperationException(); + future.completeExceptionally(origException); + CountDownLatch latch = new CountDownLatch(1); + future.whenComplete((obj, err) -> { + assertThat(obj).isNull(); + assertThat(err).isSameAs(origException); + latch.countDown(); + }); + latch.await(); + } + + @Test + public void testWriteToParcel() throws Exception { + Parcel parcel = Parcel.obtain(); + AndroidFuture<Integer> future1 = new AndroidFuture<>(); + future1.complete(5); + future1.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel); + assertThat(future2.get()).isEqualTo(5); + } + + @Test + public void testWriteToParcel_Exceptionally() throws Exception { + Parcel parcel = Parcel.obtain(); + AndroidFuture<Integer> future1 = new AndroidFuture<>(); + future1.completeExceptionally(new UnsupportedOperationException()); + future1.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel); + ExecutionException executionException = + expectThrows(ExecutionException.class, future2::get); + assertThat(executionException.getCause()).isInstanceOf(UnsupportedOperationException.class); + } +} diff --git a/data/etc/Android.bp b/data/etc/Android.bp index ff521be82599..43f65e368c10 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -88,7 +88,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.launcher3", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.launcher3.xml", filename_from_src: true, diff --git a/data/etc/CleanSpec.mk b/data/etc/CleanSpec.mk index 3fe421e530cb..b76eb1575b86 100644 --- a/data/etc/CleanSpec.mk +++ b/data/etc/CleanSpec.mk @@ -51,6 +51,8 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com. $(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.provision.xml) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.settings.xml) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.settings.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.launcher3.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.launcher3.xml) # ****************************************************************** # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER # ****************************************************************** diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml index ba877f8d0d02..ee989cca1787 100644 --- a/data/etc/com.android.settings.xml +++ b/data/etc/com.android.settings.xml @@ -51,5 +51,6 @@ <permission name="android.permission.WRITE_MEDIA_STORAGE"/> <permission name="android.permission.WRITE_SECURE_SETTINGS"/> <permission name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" /> + <permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/> </privapp-permissions> </permissions> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index cf3f51d6599a..322cbd798203 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -204,7 +204,7 @@ applications that come with the platform <permission name="android.permission.UPDATE_DEVICE_STATS"/> </privapp-permissions> - <privapp-permissions package="com.android.providers.media"> + <privapp-permissions package="com.android.providers.media.module"> <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.MANAGE_USERS"/> <permission name="android.permission.USE_RESERVED_DISK"/> @@ -369,4 +369,7 @@ applications that come with the platform <permission name="android.permission.REBOOT"/> <permission name="android.permission.MANAGE_DYNAMIC_SYSTEM"/> </privapp-permissions> + <privapp-permissions package="com.android.settings"> + <permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/> + </privapp-permissions> </permissions> diff --git a/data/sounds/AudioPackageGo.mk b/data/sounds/AudioPackageGo.mk index e3b27f2cd962..e3fb45f6f055 100644 --- a/data/sounds/AudioPackageGo.mk +++ b/data/sounds/AudioPackageGo.mk @@ -47,3 +47,7 @@ PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java index fcebad339f2b..041300c4b1b0 100644 --- a/drm/java/android/drm/DrmManagerClient.java +++ b/drm/java/android/drm/DrmManagerClient.java @@ -16,6 +16,7 @@ package android.drm; +import android.annotation.NonNull; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; @@ -37,6 +38,8 @@ import java.io.FileInputStream; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.concurrent.atomic.AtomicBoolean; @@ -370,6 +373,17 @@ public class DrmManagerClient implements AutoCloseable { } /** + * Retrieves information about all the DRM plug-ins (agents) that are + * registered with the DRM framework. + * + * @return List of all the DRM plug-ins (agents) that are registered with + * the DRM framework. + */ + public @NonNull Collection<DrmSupportInfo> getAvailableDrmSupportInfo() { + return Arrays.asList(_getAllSupportInfo(mUniqueId)); + } + + /** * Retrieves constraint information for rights-protected content. * * @param path Path to the content from which you are retrieving DRM constraints. diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 6619dba159c2..8ebac667aca3 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -1675,6 +1675,9 @@ public final class ImageDecoder implements AutoCloseable { if (r == null) { return; } + if (r.width() <= 0 || r.height() <= 0) { + throw new IllegalStateException("Subset " + r + " is empty/unsorted"); + } if (r.left < 0 || r.top < 0 || r.right > width || r.bottom > height) { throw new IllegalStateException("Subset " + r + " not contained by " + "scaled image bounds: (" + width + " x " + height + ")"); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index c0041722c475..aa1484f21862 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -125,6 +125,7 @@ public class LocationManager { * * @hide */ + @TestApi public static final String FUSED_PROVIDER = "fused"; /** @@ -164,25 +165,52 @@ public class LocationManager { * Broadcast intent action when the set of enabled location providers changes. To check the * status of a provider, use {@link #isProviderEnabled(String)}. From Android Q and above, will * include a string intent extra, {@link #EXTRA_PROVIDER_NAME}, with the name of the provider - * whose state has changed. + * whose state has changed. From Android R and above, will include a boolean intent extra, + * {@link #EXTRA_PROVIDER_ENABLED}, with the enabled state of the provider. * * @see #EXTRA_PROVIDER_NAME + * @see #EXTRA_PROVIDER_ENABLED + * @see #isProviderEnabled(String) */ public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED"; /** * Intent extra included with {@link #PROVIDERS_CHANGED_ACTION} broadcasts, containing the name - * of the location provider that has changed, to be used with location provider APIs. + * of the location provider that has changed. + * + * @see #PROVIDERS_CHANGED_ACTION + * @see #EXTRA_PROVIDER_ENABLED */ public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME"; /** - * Broadcast intent action when the device location mode changes. To check the location mode, - * use {@link #isLocationEnabled()}. + * Intent extra included with {@link #PROVIDERS_CHANGED_ACTION} broadcasts, containing the + * boolean enabled state of the location provider that has changed. + * + * @see #PROVIDERS_CHANGED_ACTION + * @see #EXTRA_PROVIDER_NAME + */ + public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED"; + + /** + * Broadcast intent action when the device location enabled state changes. From Android R and + * above, will include a boolean intent extra, {@link #EXTRA_LOCATION_ENABLED}, with the enabled + * state of location. + * + * @see #EXTRA_LOCATION_ENABLED + * @see #isLocationEnabled() */ public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED"; /** + * Intent extra included with {@link #MODE_CHANGED_ACTION} broadcasts, containing the boolean + * enabled state of location. + * + * @see #MODE_CHANGED_ACTION + */ + public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED"; + + /** * Broadcast intent action indicating that a high power location requests * has either started or stopped being active. The current state of * active location requests should be read from AppOpsManager using @@ -1810,12 +1838,9 @@ public class LocationManager { @Deprecated @RequiresPermission(ACCESS_FINE_LOCATION) public @Nullable GpsStatus getGpsStatus(@Nullable GpsStatus status) { - UnsupportedOperationException ex = new UnsupportedOperationException( - "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead"); if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) { - throw ex; - } else { - Log.w(TAG, ex); + throw new UnsupportedOperationException( + "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead"); } GnssStatus gnssStatus = mGnssStatusListenerManager.getGnssStatus(); diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java index c20dc615529b..751bb6a70880 100644 --- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java +++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java @@ -103,10 +103,6 @@ public class GnssMetrics { mPositionAccuracyMeterStatistics = new Statistics(); mTopFourAverageCn0Statistics = new Statistics(); mTopFourAverageCn0StatisticsL5 = new Statistics(); - mNumSvStatus = 0; - mNumL5SvStatus = 0; - mNumSvStatusUsedInFix = 0; - mNumL5SvStatusUsedInFix = 0; reset(); } @@ -410,6 +406,11 @@ public class GnssMetrics { mPositionAccuracyMeterStatistics.reset(); mTopFourAverageCn0Statistics.reset(); resetConstellationTypes(); + mTopFourAverageCn0StatisticsL5.reset(); + mNumSvStatus = 0; + mNumL5SvStatus = 0; + mNumSvStatusUsedInFix = 0; + mNumL5SvStatusUsedInFix = 0; } /** Resets {@link #mConstellationTypes} as an all-false boolean array. */ diff --git a/media/apex/java/android/media/MediaParser.java b/media/apex/java/android/media/MediaParser.java index 8824269ea0c0..b83f44540955 100644 --- a/media/apex/java/android/media/MediaParser.java +++ b/media/apex/java/android/media/MediaParser.java @@ -156,19 +156,29 @@ public final class MediaParser { * <p>A {@link SeekPoint} is a position in the stream from which a player may successfully start * playing media samples. */ - public interface SeekMap { + public static final class SeekMap { /** Returned by {@link #getDurationUs()} when the duration is unknown. */ - int UNKNOWN_DURATION = Integer.MIN_VALUE; + public static final int UNKNOWN_DURATION = Integer.MIN_VALUE; + + private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap; + + private SeekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) { + mExoPlayerSeekMap = exoplayerSeekMap; + } /** Returns whether seeking is supported. */ - boolean isSeekable(); + public boolean isSeekable() { + return mExoPlayerSeekMap.isSeekable(); + } /** * Returns the duration of the stream in microseconds or {@link #UNKNOWN_DURATION} if the * duration is unknown. */ - long getDurationUs(); + public long getDurationUs() { + return mExoPlayerSeekMap.getDurationUs(); + } /** * Obtains {@link SeekPoint SeekPoints} for the specified seek time in microseconds. @@ -184,7 +194,10 @@ public final class MediaParser { * @return The corresponding {@link SeekPoint SeekPoints}. */ @NonNull - Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs); + public Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs) { + SeekPoints seekPoints = mExoPlayerSeekMap.getSeekPoints(timeUs); + return new Pair<>(toSeekPoint(seekPoints.first), toSeekPoint(seekPoints.second)); + } } /** Defines a seek point in a media stream. */ @@ -647,7 +660,7 @@ public final class MediaParser { @Override public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) { - mOutputConsumer.onSeekMap(new ExoToMediaParserSeekMapAdapter(exoplayerSeekMap)); + mOutputConsumer.onSeekMap(new SeekMap(exoplayerSeekMap)); } } @@ -764,32 +777,6 @@ public final class MediaParser { Extractor createInstance(); } - private static class ExoToMediaParserSeekMapAdapter implements SeekMap { - - private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap; - - private ExoToMediaParserSeekMapAdapter( - com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) { - mExoPlayerSeekMap = exoplayerSeekMap; - } - - @Override - public boolean isSeekable() { - return mExoPlayerSeekMap.isSeekable(); - } - - @Override - public long getDurationUs() { - return mExoPlayerSeekMap.getDurationUs(); - } - - @Override - public Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs) { - SeekPoints seekPoints = mExoPlayerSeekMap.getSeekPoints(timeUs); - return new Pair<>(toSeekPoint(seekPoints.first), toSeekPoint(seekPoints.second)); - } - } - // Private static methods. private static MediaFormat toMediaFormat(Format format) { diff --git a/media/java/android/media/AudioDeviceAddress.java b/media/java/android/media/AudioDeviceAddress.java index 415e77dc4049..3d8fc373006e 100644 --- a/media/java/android/media/AudioDeviceAddress.java +++ b/media/java/android/media/AudioDeviceAddress.java @@ -72,10 +72,12 @@ public final class AudioDeviceAddress implements Parcelable { private final @Role int mRole; /** + * @hide * Constructor from a valid {@link AudioDeviceInfo} * @param deviceInfo the connected audio device from which to obtain the device-identifying * type and address. */ + @SystemApi public AudioDeviceAddress(@NonNull AudioDeviceInfo deviceInfo) { Objects.requireNonNull(deviceInfo); mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT; @@ -83,6 +85,14 @@ public final class AudioDeviceAddress implements Parcelable { mAddress = deviceInfo.getAddress(); } + /** + * @hide + * Constructor from role, device type and address + * @param role indicates input or output role + * @param type the device type, as defined in {@link AudioDeviceInfo} + * @param address the address of the device, or an empty string for devices without one + */ + @SystemApi public AudioDeviceAddress(@Role int role, @AudioDeviceInfo.AudioDeviceType int type, @NonNull String address) { Objects.requireNonNull(address); @@ -101,14 +111,38 @@ public final class AudioDeviceAddress implements Parcelable { mAddress = address; } + /*package*/ AudioDeviceAddress(int nativeType, @NonNull String address) { + mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT; + mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType); + mAddress = address; + } + + /** + * @hide + * Returns the role of a device + * @return the role + */ + @SystemApi public @Role int getRole() { return mRole; } + /** + * @hide + * Returns the audio device type of a device + * @return the type, as defined in {@link AudioDeviceInfo} + */ + @SystemApi public @AudioDeviceInfo.AudioDeviceType int getType() { return mType; } + /** + * @hide + * Returns the address of the audio device, or an empty string for devices without one + * @return the device address + */ + @SystemApi public @NonNull String getAddress() { return mAddress; } diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index a39bc51acb24..8293b5f36c04 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -155,7 +155,9 @@ public final class AudioDeviceInfo { TYPE_TV_TUNER } ) @Retention(RetentionPolicy.SOURCE) - public @interface AudioDeviceType {} /** @hide */ + public @interface AudioDeviceType {} + + /** @hide */ @IntDef(flag = false, prefix = "TYPE", value = { TYPE_BUILTIN_MIC, TYPE_BLUETOOTH_SCO, diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index d5524915f423..fac276cfb5d1 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -78,6 +78,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; @@ -1536,6 +1537,76 @@ public class AudioManager { } //==================================================================== + // Audio Product Strategy routing + + /** + * @hide + * Set the preferred device for a given strategy, i.e. the audio routing to be used by + * this audio strategy. Note that the device may not be available at the time the preferred + * device is set, but it will be used once made available. + * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting + * this preference for this strategy.</p> + * @param strategy the audio strategy whose routing will be affected + * @param device the audio device to route to when available + * @return true if the operation was successful, false otherwise + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy, + @NonNull AudioDeviceAddress device) { + Objects.requireNonNull(strategy); + Objects.requireNonNull(device); + try { + final int status = + getService().setPreferredDeviceForStrategy(strategy.getId(), device); + return status == AudioSystem.SUCCESS; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + * Removes the preferred audio device previously set with + * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAddress)}. + * @param strategy the audio strategy whose routing will be affected + * @return true if the operation was successful, false otherwise (invalid strategy, or no + * device set for example) + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) { + Objects.requireNonNull(strategy); + try { + final int status = + getService().removePreferredDeviceForStrategy(strategy.getId()); + return status == AudioSystem.SUCCESS; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + * Return the preferred device for an audio strategy, previously set with + * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAddress)} + * @param strategy the strategy to query + * @return the preferred device for that strategy, or null if none was ever set or if the + * strategy is invalid + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public @Nullable AudioDeviceAddress getPreferredDeviceForStrategy( + @NonNull AudioProductStrategy strategy) { + Objects.requireNonNull(strategy); + try { + return getService().getPreferredDeviceForStrategy(strategy.getId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + //==================================================================== // Offload query /** * Returns whether offloaded playback of an audio format is supported on the device. @@ -4962,6 +5033,14 @@ public class AudioManager { */ public static final int GET_DEVICES_OUTPUTS = 0x0002; + /** @hide */ + @IntDef(flag = true, prefix = "GET_DEVICES", value = { + GET_DEVICES_INPUTS, + GET_DEVICES_OUTPUTS } + ) + @Retention(RetentionPolicy.SOURCE) + public @interface AudioDeviceRole {} + /** * Specifies to the {@link AudioManager#getDevices(int)} method to include both * source and sink devices. @@ -4994,7 +5073,7 @@ public class AudioManager { * @see #GET_DEVICES_ALL * @return A (possibly zero-length) array of AudioDeviceInfo objects. */ - public AudioDeviceInfo[] getDevices(int flags) { + public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) { return getDevicesStatic(flags); } diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index d64e4ef00164..066bf25179a6 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -1173,6 +1173,48 @@ public class AudioSystem */ public static native boolean isCallScreeningModeSupported(); + // use case routing by product strategy + + /** + * Sets the preferred device to use for a given audio strategy in the audio policy engine + * @param strategy the id of the strategy to configure + * @param device the device type and address to route to when available + * @return {@link #SUCCESS} if successfully set + */ + public static int setPreferredDeviceForStrategy( + int strategy, @NonNull AudioDeviceAddress device) { + return setPreferredDeviceForStrategy(strategy, + AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType()), + device.getAddress()); + } + /** + * Set device routing per product strategy. + * @param strategy the id of the strategy to configure + * @param deviceType the native device type, NOT AudioDeviceInfo types + * @param deviceAddress the address of the device + * @return {@link #SUCCESS} if successfully set + */ + private static native int setPreferredDeviceForStrategy( + int strategy, int deviceType, String deviceAddress); + + /** + * Remove preferred routing for the strategy + * @param strategy the id of the strategy to configure + * @return {@link #SUCCESS} if successfully removed + */ + public static native int removePreferredDeviceForStrategy(int strategy); + + /** + * Query previously set preferred device for a strategy + * @param strategy the id of the strategy to query for + * @param device an array of size 1 that will contain the preferred device, or null if + * none was set + * @return {@link #SUCCESS} if there is a preferred device and it was successfully retrieved + * and written to the array + */ + public static native int getPreferredDeviceForStrategy(int strategy, + AudioDeviceAddress[] device); + // Items shared with audio service /** diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index ef451ce401e6..ad7335e5b683 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -18,6 +18,7 @@ package android.media; import android.bluetooth.BluetoothDevice; import android.media.AudioAttributes; +import android.media.AudioDeviceAddress; import android.media.AudioFocusInfo; import android.media.AudioPlaybackConfiguration; import android.media.AudioRecordingConfiguration; @@ -265,6 +266,12 @@ interface IAudioService { boolean isCallScreeningModeSupported(); + int setPreferredDeviceForStrategy(in int strategy, in AudioDeviceAddress device); + + int removePreferredDeviceForStrategy(in int strategy); + + AudioDeviceAddress getPreferredDeviceForStrategy(in int strategy); + // WARNING: read warning at top of file, new methods that need to be used by native // code via IAudioManager.h need to be added to the top section. } diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 8080f45642dc..94a6f134a1b6 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -99,6 +99,8 @@ import java.util.stream.Collectors; * <tr><td>{@link #KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the maximum number of channels the decoder outputs.</td></tr> * <tr><td>{@link #KEY_AAC_DRC_EFFECT_TYPE}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the MPEG-D DRC effect type to use.</td></tr> * <tr><td>{@link #KEY_CHANNEL_MASK}</td><td>Integer</td><td>optional, a mask of audio channel assignments</td></tr> + * <tr><td>{@link #KEY_ENCODER_DELAY}</td><td>Integer</td><td>optional, the number of frames to trim from the start of the decoded audio stream.</td></tr> + * <tr><td>{@link #KEY_ENCODER_PADDING}</td><td>Integer</td><td>optional, the number of frames to trim from the end of the decoded audio stream.</td></tr> * <tr><td>{@link #KEY_FLAC_COMPRESSION_LEVEL}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is FLAC audio, specifies the desired compression level.</td></tr> * </table> * @@ -569,6 +571,18 @@ public final class MediaFormat { public static final String KEY_CHANNEL_MASK = "channel-mask"; /** + * A key describing the number of frames to trim from the start of the decoded audio stream. + * The associated value is an integer. + */ + public static final String KEY_ENCODER_DELAY = "encoder-delay"; + + /** + * A key describing the number of frames to trim from the end of the decoded audio stream. + * The associated value is an integer. + */ + public static final String KEY_ENCODER_PADDING = "encoder-padding"; + + /** * A key describing the AAC profile to be used (AAC audio formats only). * Constants are declared in {@link android.media.MediaCodecInfo.CodecProfileLevel}. */ diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java index 8d857243bc05..515f6a8ce8a2 100644 --- a/media/java/android/media/MediaScannerConnection.java +++ b/media/java/android/media/MediaScannerConnection.java @@ -164,7 +164,7 @@ public class MediaScannerConnection implements ServiceConnection { /** * Convenience for constructing a {@link MediaScannerConnection}, calling - * {@link #connect} on it, and calling {@link #scanFile} with the given + * {@link #connect} on it, and calling {@link #scanFile(String, String)} with the given * <var>path</var> and <var>mimeType</var> when the connection is * established. * @param context The caller's Context, required for establishing a connection to diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java index 2799d46cbb47..612f83a14e12 100644 --- a/media/java/android/media/audiopolicy/AudioProductStrategy.java +++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java @@ -19,6 +19,7 @@ package android.media.audiopolicy; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.media.AudioAttributes; import android.media.AudioSystem; import android.media.MediaRecorder; @@ -82,6 +83,18 @@ public final class AudioProductStrategy implements Parcelable { /** * @hide + * Create an invalid AudioProductStrategy instance for testing + * @param id the ID for the invalid strategy, always use a different one than in use + * @return an invalid instance that cannot successfully be used for volume groups or routing + */ + @TestApi + @SystemApi + public static @NonNull AudioProductStrategy createInvalidAudioProductStrategy(int id) { + return new AudioProductStrategy("dummy strategy", id, new AudioAttributesGroup[0]); + } + + /** + * @hide * @param streamType to match against AudioProductStrategy * @return the AudioAttributes for the first strategy found with the associated stream type * If no match is found, returns AudioAttributes with unknown content_type and usage @@ -222,6 +235,7 @@ public final class AudioProductStrategy implements Parcelable { * @return true if the {@link AudioProductStrategy} supports the given {@link AudioAttributes}, * false otherwise. */ + @SystemApi public boolean supportsAudioAttributes(@NonNull AudioAttributes aa) { Preconditions.checkNotNull(aa, "AudioAttributes must not be null"); for (final AudioAttributesGroup aag : mAudioAttributesGroups) { diff --git a/media/java/android/media/tv/tuner/DvrSettings.java b/media/java/android/media/tv/tuner/DvrSettings.java new file mode 100644 index 000000000000..76160dc9fcf8 --- /dev/null +++ b/media/java/android/media/tv/tuner/DvrSettings.java @@ -0,0 +1,124 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.tv.tuner; + +import android.media.tv.tuner.TunerConstants.DataFormat; +import android.media.tv.tuner.TunerConstants.DvrSettingsType; + +/** + * DVR settings. + * + * @hide + */ +public class DvrSettings { + private int mStatusMask; + private int mLowThreshold; + private int mHighThreshold; + private int mPacketSize; + + @DataFormat + private int mDataFormat; + @DvrSettingsType + private int mType; + + private DvrSettings(int statusMask, int lowThreshold, int highThreshold, int packetSize, + @DataFormat int dataFormat, @DvrSettingsType int type) { + mStatusMask = statusMask; + mLowThreshold = lowThreshold; + mHighThreshold = highThreshold; + mPacketSize = packetSize; + mDataFormat = dataFormat; + mType = type; + } + + /** + * Creates a new builder. + */ + public static Builder newBuilder() { + return new Builder(); + } + + /** + * Builder for DvrSettings. + */ + public static final class Builder { + private int mStatusMask; + private int mLowThreshold; + private int mHighThreshold; + private int mPacketSize; + @DataFormat + private int mDataFormat; + @DvrSettingsType + private int mType; + + /** + * Sets status mask. + */ + public Builder setStatusMask(int statusMask) { + this.mStatusMask = statusMask; + return this; + } + + /** + * Sets low threshold. + */ + public Builder setLowThreshold(int lowThreshold) { + this.mLowThreshold = lowThreshold; + return this; + } + + /** + * Sets high threshold. + */ + public Builder setHighThreshold(int highThreshold) { + this.mHighThreshold = highThreshold; + return this; + } + + /** + * Sets packet size. + */ + public Builder setPacketSize(int packetSize) { + this.mPacketSize = packetSize; + return this; + } + + /** + * Sets data format. + */ + public Builder setDataFormat(@DataFormat int dataFormat) { + this.mDataFormat = dataFormat; + return this; + } + + /** + * Sets settings type. + */ + public Builder setType(@DvrSettingsType int type) { + this.mType = type; + return this; + } + + /** + * Builds a DvrSettings instance. + */ + public DvrSettings build() { + return new DvrSettings( + mStatusMask, mLowThreshold, mHighThreshold, mPacketSize, mDataFormat, mType); + } + } +} diff --git a/media/java/android/media/tv/tuner/FilterSettings.java b/media/java/android/media/tv/tuner/FilterSettings.java new file mode 100644 index 000000000000..d5f100341dc6 --- /dev/null +++ b/media/java/android/media/tv/tuner/FilterSettings.java @@ -0,0 +1,383 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.tv.tuner; + +import android.annotation.Nullable; +import android.hardware.tv.tuner.V1_0.Constants; +import android.media.tv.tuner.TunerConstants.FilterSettingsType; + +import java.util.List; + +/** + * Demux Filter settings. + * + * @hide + */ +public abstract class FilterSettings { + @Nullable + protected final Settings mSettings; + + protected FilterSettings(Settings settings) { + mSettings = settings; + } + + /** + * Gets filter settings type + */ + @FilterSettingsType public abstract int getType(); + + // TODO: more builders and getters + + /** + * Filter Settings for a TS filter. + */ + public static class TsFilterSettings extends FilterSettings { + private int mTpid; + + private TsFilterSettings(Settings settings, int tpid) { + super(settings); + mTpid = tpid; + } + + @Override + public int getType() { + return TunerConstants.FILTER_SETTINGS_TS; + } + + /** + * Creates a new builder. + */ + public static Builder newBuilder() { + return new Builder(); + } + + /** + * Builder for TsFilterSettings. + */ + public static class Builder { + private Settings mSettings; + private int mTpid; + + /** + * Sets settings. + */ + public Builder setSettings(Settings settings) { + mSettings = settings; + return this; + } + + /** + * Sets TPID. + */ + public Builder setTpid(int tpid) { + mTpid = tpid; + return this; + } + + /** + * Builds a TsFilterSettings instance. + */ + public TsFilterSettings build() { + return new TsFilterSettings(mSettings, mTpid); + } + } + } + + /** + * Filter Settings for a MMTP filter. + */ + public static class MmtpFilterSettings extends FilterSettings { + private int mMmtpPid; + + public MmtpFilterSettings(Settings settings) { + super(settings); + } + + @Override + public int getType() { + return TunerConstants.FILTER_SETTINGS_MMTP; + } + } + + + /** + * Filter Settings for a IP filter. + */ + public static class IpFilterSettings extends FilterSettings { + private byte[] mSrcIpAddress; + private byte[] mDstIpAddress; + private int mSrcPort; + private int mDstPort; + private boolean mPassthrough; + + public IpFilterSettings(Settings settings) { + super(settings); + } + + @Override + public int getType() { + return TunerConstants.FILTER_SETTINGS_IP; + } + } + + + /** + * Filter Settings for a TLV filter. + */ + public static class TlvFilterSettings extends FilterSettings { + private int mPacketType; + private boolean mIsCompressedIpPacket; + private boolean mPassthrough; + + public TlvFilterSettings(Settings settings) { + super(settings); + } + + @Override + public int getType() { + return TunerConstants.FILTER_SETTINGS_TLV; + } + } + + + /** + * Filter Settings for a ALP filter. + */ + public static class AlpFilterSettings extends FilterSettings { + private int mPacketType; + private int mLengthType; + + public AlpFilterSettings(Settings settings) { + super(settings); + } + + @Override + public int getType() { + return TunerConstants.FILTER_SETTINGS_ALP; + } + } + + + /** + * Settings for filters of different subtypes. + */ + public abstract static class Settings { + protected final int mType; + + protected Settings(int type) { + mType = type; + } + + /** + * Gets filter settings type. + * @return + */ + int getType() { + return mType; + } + } + + /** + * Filter Settings for Section data according to ISO/IEC 13818-1. + */ + public static class SectionSettings extends Settings { + + private SectionSettings(int mainType) { + super(SectionSettings.findType(mainType)); + } + + private static int findType(int mainType) { + switch (mainType) { + case TunerConstants.FILTER_SETTINGS_TS: + return Constants.DemuxTsFilterType.SECTION; + case TunerConstants.FILTER_SETTINGS_MMTP: + return Constants.DemuxMmtpFilterType.SECTION; + case TunerConstants.FILTER_SETTINGS_IP: + return Constants.DemuxIpFilterType.SECTION; + case TunerConstants.FILTER_SETTINGS_TLV: + return Constants.DemuxTlvFilterType.SECTION; + case TunerConstants.FILTER_SETTINGS_ALP: + return Constants.DemuxAlpFilterType.SECTION; + } + // UNDEFINED + return 0; + } + } + + /** + * Bits Settings for Section Filter. + */ + public static class SectionSettingsWithSectionBits extends SectionSettings { + private List<Byte> mFilter; + private List<Byte> mMask; + private List<Byte> mMode; + + private SectionSettingsWithSectionBits(int mainType) { + super(mainType); + } + } + + /** + * Table information for Section Filter. + */ + public static class SectionSettingsWithTableInfo extends SectionSettings { + private int mTableId; + private int mVersion; + + private SectionSettingsWithTableInfo(int mainType) { + super(mainType); + } + } + + /** + * Filter Settings for a PES Data. + */ + public static class PesSettings extends Settings { + private int mStreamId; + private boolean mIsRaw; + + private PesSettings(int mainType, int streamId, boolean isRaw) { + super(PesSettings.findType(mainType)); + mStreamId = streamId; + mIsRaw = isRaw; + } + + private static int findType(int mainType) { + switch (mainType) { + case TunerConstants.FILTER_SETTINGS_TS: + return Constants.DemuxTsFilterType.PES; + case TunerConstants.FILTER_SETTINGS_MMTP: + return Constants.DemuxMmtpFilterType.PES; + } + // UNDEFINED + return 0; + } + + /** + * Creates a builder for PesSettings. + */ + public static Builder newBuilder(int mainType) { + return new Builder(mainType); + } + + /** + * Builder for PesSettings. + */ + public static class Builder { + private final int mMainType; + private int mStreamId; + private boolean mIsRaw; + + public Builder(int mainType) { + mMainType = mainType; + } + + /** + * Sets stream ID. + */ + public Builder setStreamId(int streamId) { + mStreamId = streamId; + return this; + } + + /** + * Sets whether it's raw. + * true if the filter send onFilterStatus instead of onFilterEvent. + */ + public Builder setIsRaw(boolean isRaw) { + mIsRaw = isRaw; + return this; + } + + /** + * Builds a PesSettings instance. + */ + public PesSettings build() { + return new PesSettings(mMainType, mStreamId, mIsRaw); + } + } + } + + /** + * Filter Settings for a Video and Audio. + */ + public static class AvSettings extends Settings { + private boolean mIsPassthrough; + + private AvSettings(int mainType, boolean isAudio) { + super(AvSettings.findType(mainType, isAudio)); + } + + private static int findType(int mainType, boolean isAudio) { + switch (mainType) { + case TunerConstants.FILTER_SETTINGS_TS: + return isAudio + ? Constants.DemuxTsFilterType.AUDIO + : Constants.DemuxTsFilterType.VIDEO; + case TunerConstants.FILTER_SETTINGS_MMTP: + return isAudio + ? Constants.DemuxMmtpFilterType.AUDIO + : Constants.DemuxMmtpFilterType.VIDEO; + } + // UNDEFINED + return 0; + } + } + + /** + * Filter Settings for a Download. + */ + public static class DownloadSettings extends Settings { + private int mDownloadId; + + public DownloadSettings(int mainType) { + super(DownloadSettings.findType(mainType)); + } + + private static int findType(int mainType) { + if (mainType == TunerConstants.FILTER_SETTINGS_MMTP) { + return Constants.DemuxMmtpFilterType.DOWNLOAD; + } + // UNDEFINED + return 0; + } + } + + /** + * The Settings for the record in DVR. + */ + public static class RecordSettings extends Settings { + private int mIndexType; + private int mIndexMask; + + public RecordSettings(int mainType) { + super(RecordSettings.findType(mainType)); + } + + private static int findType(int mainType) { + switch (mainType) { + case TunerConstants.FILTER_SETTINGS_TS: + return Constants.DemuxTsFilterType.RECORD; + case TunerConstants.FILTER_SETTINGS_MMTP: + return Constants.DemuxMmtpFilterType.RECORD; + } + // UNDEFINED + return 0; + } + } + +} diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 82cef2e43307..4c93101bc0b5 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -243,9 +243,11 @@ public final class Tuner implements AutoCloseable { private FilterCallback mCallback; int mId; + private native int nativeConfigureFilter(int type, int subType, FilterSettings settings); private native boolean nativeStartFilter(); private native boolean nativeStopFilter(); private native boolean nativeFlushFilter(); + private native int nativeRead(byte[] buffer, int offset, int size); private Filter(int id) { mId = id; @@ -258,6 +260,14 @@ public final class Tuner implements AutoCloseable { } } + public int configure(FilterSettings settings) { + int subType = -1; + if (settings.mSettings != null) { + subType = settings.mSettings.getType(); + } + return nativeConfigureFilter(settings.getType(), subType, settings); + } + public boolean start() { return nativeStartFilter(); } @@ -269,6 +279,11 @@ public final class Tuner implements AutoCloseable { public boolean flush() { return nativeFlushFilter(); } + + public int read(@NonNull byte[] buffer, int offset, int size) { + size = Math.min(size, buffer.length - offset); + return nativeRead(buffer, offset, size); + } } private Filter openFilter(int type, int subType, int bufferSize, FilterCallback cb) { @@ -353,6 +368,7 @@ public final class Tuner implements AutoCloseable { private native boolean nativeAttachFilter(Filter filter); private native boolean nativeDetachFilter(Filter filter); + private native int nativeConfigureDvr(DvrSettings settings); private native boolean nativeStartDvr(); private native boolean nativeStopDvr(); private native boolean nativeFlushDvr(); @@ -365,6 +381,9 @@ public final class Tuner implements AutoCloseable { public boolean detachFilter(Filter filter) { return nativeDetachFilter(filter); } + public int configure(DvrSettings settings) { + return nativeConfigureDvr(settings); + } public boolean start() { return nativeStartDvr(); } diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java index 458cb1678ded..261b2deebac9 100644 --- a/media/java/android/media/tv/tuner/TunerConstants.java +++ b/media/java/android/media/tv/tuner/TunerConstants.java @@ -90,6 +90,24 @@ final class TunerConstants { public static final int FRONTEND_SETTINGS_ISDBS3 = 8; public static final int FRONTEND_SETTINGS_ISDBT = 9; + @Retention(RetentionPolicy.SOURCE) + @IntDef({FILTER_SETTINGS_TS, FILTER_SETTINGS_MMTP, FILTER_SETTINGS_IP, FILTER_SETTINGS_TLV, + FILTER_SETTINGS_ALP}) + public @interface FilterSettingsType {} + + public static final int FILTER_SETTINGS_TS = Constants.DemuxFilterMainType.TS; + public static final int FILTER_SETTINGS_MMTP = Constants.DemuxFilterMainType.MMTP; + public static final int FILTER_SETTINGS_IP = Constants.DemuxFilterMainType.IP; + public static final int FILTER_SETTINGS_TLV = Constants.DemuxFilterMainType.TLV; + public static final int FILTER_SETTINGS_ALP = Constants.DemuxFilterMainType.ALP; + + @Retention(RetentionPolicy.SOURCE) + @IntDef({DVR_SETTINGS_RECORD, DVR_SETTINGS_PLAYBACK}) + public @interface DvrSettingsType {} + + public static final int DVR_SETTINGS_RECORD = Constants.DvrType.RECORD; + public static final int DVR_SETTINGS_PLAYBACK = Constants.DvrType.PLAYBACK; + private TunerConstants() { } } diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 12b3e6735d81..4ca23a1084a2 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -135,6 +135,8 @@ cc_library_shared { shared_libs: [ "android.hardware.tv.tuner@1.0", "libandroid_runtime", + "libcutils", + "libfmq", "libhidlbase", "liblog", "libutils", diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp index 5ddfcfce072e..d3151545333c 100644 --- a/media/jni/android_media_MediaMetricsJNI.cpp +++ b/media/jni/android_media_MediaMetricsJNI.cpp @@ -16,213 +16,112 @@ #define LOG_TAG "MediaMetricsJNI" +#include <binder/Parcel.h> #include <jni.h> +#include <media/MediaAnalyticsItem.h> #include <nativehelper/JNIHelp.h> #include "android_media_MediaMetricsJNI.h" #include "android_os_Parcel.h" -#include <media/MediaAnalyticsItem.h> -#include <binder/Parcel.h> - // This source file is compiled and linked into: // core/jni/ (libandroid_runtime.so) namespace android { -// place the attributes into a java PersistableBundle object -jobject MediaMetricsJNI::writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle) { - - jclass clazzBundle = env->FindClass("android/os/PersistableBundle"); - if (clazzBundle==NULL) { - ALOGE("can't find android/os/PersistableBundle"); - return NULL; +namespace { +struct BundleHelper { + BundleHelper(JNIEnv* _env, jobject _bundle) + : env(_env) + , clazzBundle(env->FindClass("android/os/PersistableBundle")) + , putIntID(env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V")) + , putLongID(env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V")) + , putDoubleID(env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V")) + , putStringID(env->GetMethodID(clazzBundle, + "putString", "(Ljava/lang/String;Ljava/lang/String;)V")) + , constructID(env->GetMethodID(clazzBundle, "<init>", "()V")) + , bundle(_bundle == nullptr ? env->NewObject(clazzBundle, constructID) : _bundle) + { } + + JNIEnv* const env; + const jclass clazzBundle; + const jmethodID putIntID; + const jmethodID putLongID; + const jmethodID putDoubleID; + const jmethodID putStringID; + const jmethodID constructID; + jobject const bundle; + + // We use templated put to access MediaAnalyticsItem based on data type not type enum. + // See std::variant and std::visit. + template<typename T> + void put(jstring keyName, const T& value) = delete; + + template<> + void put(jstring keyName, const int32_t& value) { + env->CallVoidMethod(bundle, putIntID, keyName, (jint)value); } - // sometimes the caller provides one for us to fill - if (mybundle == NULL) { - // create the bundle - jmethodID constructID = env->GetMethodID(clazzBundle, "<init>", "()V"); - mybundle = env->NewObject(clazzBundle, constructID); - if (mybundle == NULL) { - return NULL; - } - } - - // grab methods that we can invoke - jmethodID setIntID = env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V"); - jmethodID setLongID = env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V"); - jmethodID setDoubleID = env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V"); - jmethodID setStringID = env->GetMethodID(clazzBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V"); - // env, class, method, {parms} - //env->CallVoidMethod(env, mybundle, setIntID, jstr, jint); - - // iterate through my attributes - // -- get name, get type, get value - // -- insert appropriately into the bundle - for (size_t i = 0 ; i < item->mPropCount; i++ ) { - MediaAnalyticsItem::Prop *prop = &item->mProps[i]; - // build the key parameter from prop->mName - jstring keyName = env->NewStringUTF(prop->mName); - // invoke the appropriate method to insert - switch (prop->mType) { - case MediaAnalyticsItem::kTypeInt32: - env->CallVoidMethod(mybundle, setIntID, - keyName, (jint) prop->u.int32Value); - break; - case MediaAnalyticsItem::kTypeInt64: - env->CallVoidMethod(mybundle, setLongID, - keyName, (jlong) prop->u.int64Value); - break; - case MediaAnalyticsItem::kTypeDouble: - env->CallVoidMethod(mybundle, setDoubleID, - keyName, (jdouble) prop->u.doubleValue); - break; - case MediaAnalyticsItem::kTypeCString: - env->CallVoidMethod(mybundle, setStringID, keyName, - env->NewStringUTF(prop->u.CStringValue)); - break; - default: - ALOGE("to_String bad item type: %d for %s", - prop->mType, prop->mName); - break; - } + template<> + void put(jstring keyName, const int64_t& value) { + env->CallVoidMethod(bundle, putLongID, keyName, (jlong)value); } - return mybundle; -} - -// convert the specified batch metrics attributes to a persistent bundle. -// The encoding of the byte array is specified in -// frameworks/av/media/libmediametrics/MediaAnalyticsItem.cpp -// -// type encodings; matches frameworks/av/media/libmediametrics/MediaAnalyticsItem.cpp -enum { kInt32 = 0, kInt64, kDouble, kRate, kCString}; - -jobject MediaMetricsJNI::writeAttributesToBundle(JNIEnv* env, jobject mybundle, char *buffer, size_t length) { - ALOGV("writeAttributes()"); - - if (buffer == NULL || length <= 0) { - ALOGW("bad parameters to writeAttributesToBundle()"); - return NULL; + template<> + void put(jstring keyName, const double& value) { + env->CallVoidMethod(bundle, putDoubleID, keyName, (jdouble)value); } - jclass clazzBundle = env->FindClass("android/os/PersistableBundle"); - if (clazzBundle==NULL) { - ALOGE("can't find android/os/PersistableBundle"); - return NULL; - } - // sometimes the caller provides one for us to fill - if (mybundle == NULL) { - // create the bundle - jmethodID constructID = env->GetMethodID(clazzBundle, "<init>", "()V"); - mybundle = env->NewObject(clazzBundle, constructID); - if (mybundle == NULL) { - ALOGD("unable to create mybundle"); - return NULL; - } + template<> + void put(jstring keyName, const char * const& value) { + env->CallVoidMethod(bundle, putStringID, keyName, env->NewStringUTF(value)); } - int left = length; - char *buf = buffer; + template<> + void put(jstring keyName, char * const& value) { + env->CallVoidMethod(bundle, putStringID, keyName, env->NewStringUTF(value)); + } - // grab methods that we can invoke - jmethodID setIntID = env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V"); - jmethodID setLongID = env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V"); - jmethodID setDoubleID = env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V"); - jmethodID setStringID = env->GetMethodID(clazzBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V"); + template<> + void put(jstring keyName, const std::pair<int64_t, int64_t>& value) { + ; // rate is currently ignored + } + // We allow both jstring and non-jstring variants. + template<typename T> + void put(const char *keyName, const T& value) { + put(env->NewStringUTF(keyName), value); + } +}; +} // namespace -#define _EXTRACT(size, val) \ - { if ((size) > left) goto badness; memcpy(&val, buf, (size)); buf += (size); left -= (size);} -#define _SKIP(size) \ - { if ((size) > left) goto badness; buf += (size); left -= (size);} +// place the attributes into a java PersistableBundle object +jobject MediaMetricsJNI::writeMetricsToBundle( + JNIEnv* env, MediaAnalyticsItem *item, jobject bundle) +{ + BundleHelper bh(env, bundle); + + if (bh.bundle == nullptr) { + ALOGE("%s: unable to create Bundle", __func__); + return nullptr; + } - int32_t bufsize; - _EXTRACT(sizeof(int32_t), bufsize); - if (bufsize != length) { - goto badness; + bh.put("__key", item->getKey().c_str()); + if (item->getPid() != -1) { + bh.put("__pid", (int32_t)item->getPid()); } - int32_t proto; - _EXTRACT(sizeof(int32_t), proto); - if (proto != 0) { - ALOGE("unsupported wire protocol %d", proto); - goto badness; + if (item->getTimestamp() > 0) { + bh.put("__timestamp", (int64_t)item->getTimestamp()); } - - int32_t count; - _EXTRACT(sizeof(int32_t), count); - - // iterate through my attributes - // -- get name, get type, get value, insert into bundle appropriately. - for (int i = 0 ; i < count; i++ ) { - // prop name len (int16) - int16_t keylen; - _EXTRACT(sizeof(int16_t), keylen); - if (keylen <= 0) goto badness; - // prop name itself - char *key = buf; - jstring keyName = env->NewStringUTF(buf); - _SKIP(keylen); - - // prop type (int8_t) - int8_t attrType; - _EXTRACT(sizeof(int8_t), attrType); - - int16_t attrSize; - _EXTRACT(sizeof(int16_t), attrSize); - - switch (attrType) { - case kInt32: - { - int32_t i32; - _EXTRACT(sizeof(int32_t), i32); - env->CallVoidMethod(mybundle, setIntID, - keyName, (jint) i32); - break; - } - case kInt64: - { - int64_t i64; - _EXTRACT(sizeof(int64_t), i64); - env->CallVoidMethod(mybundle, setLongID, - keyName, (jlong) i64); - break; - } - case kDouble: - { - double d64; - _EXTRACT(sizeof(double), d64); - env->CallVoidMethod(mybundle, setDoubleID, - keyName, (jdouble) d64); - break; - } - case kCString: - { - jstring value = env->NewStringUTF(buf); - env->CallVoidMethod(mybundle, setStringID, - keyName, value); - _SKIP(attrSize); - break; - } - default: - ALOGW("ignoring Attribute '%s' unknown type: %d", - key, attrType); - _SKIP(attrSize); - break; - } + if (item->getUid() != -1) { + bh.put("__uid", (int32_t)item->getUid()); } - - // should have consumed it all - if (left != 0) { - ALOGW("did not consume entire buffer; left(%d) != 0", left); - goto badness; + for (const auto &prop : *item) { + const char *name = prop.getName(); + if (name == nullptr) continue; + prop.visit([&] (auto &value) { bh.put(name, value); }); } - - return mybundle; - - badness: - return NULL; + return bh.bundle; } // Helper function to convert a native PersistableBundle to a Java diff --git a/media/jni/android_media_MediaMetricsJNI.h b/media/jni/android_media_MediaMetricsJNI.h index e879da01c6ef..63ec27aa58ee 100644 --- a/media/jni/android_media_MediaMetricsJNI.h +++ b/media/jni/android_media_MediaMetricsJNI.h @@ -28,7 +28,6 @@ namespace android { class MediaMetricsJNI { public: static jobject writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle); - static jobject writeAttributesToBundle(JNIEnv* env, jobject mybundle, char *buffer, size_t length); static jobject nativeToJavaPersistableBundle(JNIEnv*, os::PersistableBundle*); }; diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index 5216906d5ec5..5fa6a1f03329 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -27,14 +27,22 @@ using ::android::hardware::Void; using ::android::hardware::hidl_vec; +using ::android::hardware::tv::tuner::V1_0::DataFormat; using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType; +using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; +using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using ::android::hardware::tv::tuner::V1_0::DemuxMmtpPid; +using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; using ::android::hardware::tv::tuner::V1_0::DemuxTpid; +using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType; +using ::android::hardware::tv::tuner::V1_0::DvrSettings; using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSettings; using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard; using ::android::hardware::tv::tuner::V1_0::FrontendAnalogType; using ::android::hardware::tv::tuner::V1_0::ITuner; +using ::android::hardware::tv::tuner::V1_0::PlaybackSettings; +using ::android::hardware::tv::tuner::V1_0::RecordSettings; using ::android::hardware::tv::tuner::V1_0::Result; struct fields_t { @@ -112,6 +120,26 @@ void FilterCallback::setFilter(const jobject filter) { mFilter = env->NewWeakGlobalRef(filter); } +/////////////// Filter /////////////////////// + +Filter::Filter(sp<IFilter> sp, jweak obj) : mFilterSp(sp), mFilterObj(obj) {} + +Filter::~Filter() { + EventFlag::deleteEventFlag(&mFilterMQEventFlag); +} + +int Filter::close() { + Result r = mFilterSp->close(); + if (r == Result::SUCCESS) { + EventFlag::deleteEventFlag(&mFilterMQEventFlag); + } + return (int)r; +} + +sp<IFilter> Filter::getIFilter() { + return mFilterSp; +} + /////////////// FrontendCallback /////////////////////// FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {} @@ -211,6 +239,7 @@ jobject JTuner::openFrontendById(int id) { fe->setCallback(feCb); jint jId = (jint) id; + JNIEnv *env = AndroidRuntime::getJNIEnv(); // TODO: add more fields to frontend return env->NewObject( @@ -327,18 +356,18 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { } } - sp<IFilter> filterSp; + sp<IFilter> iFilterSp; sp<FilterCallback> callback = new FilterCallback(); mDemux->openFilter(type, bufferSize, callback, [&](Result, const sp<IFilter>& filter) { - filterSp = filter; + iFilterSp = filter; }); - if (filterSp == NULL) { + if (iFilterSp == NULL) { ALOGD("Failed to open filter, type = %d", type.mainType); return NULL; } int fId; - filterSp->getId([&](Result, uint32_t filterId) { + iFilterSp->getId([&](Result, uint32_t filterId) { fId = filterId; }); @@ -350,6 +379,7 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { mObject, (jint) fId); + sp<Filter> filterSp = new Filter(iFilterSp, filterObj); filterSp->incStrong(filterObj); env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get()); @@ -432,7 +462,7 @@ static DemuxPid getDemuxPid(int pidType, int pid) { static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject settings) { FrontendSettings frontendSettings; jclass clazz = env->FindClass("android/media/tv/tuner/FrontendSettings"); - jfieldID freqField = env->GetFieldID(clazz, "frequency", "I"); + jfieldID freqField = env->GetFieldID(clazz, "mFrequency", "I"); uint32_t freq = static_cast<uint32_t>(env->GetIntField(clazz, freqField)); // TODO: handle the other 8 types of settings @@ -455,8 +485,51 @@ static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject setti return frontendSettings; } -static sp<IFilter> getFilter(JNIEnv *env, jobject filter) { - return (IFilter *)env->GetLongField(filter, gFields.filterContext); +static sp<Filter> getFilter(JNIEnv *env, jobject filter) { + return (Filter *)env->GetLongField(filter, gFields.filterContext); +} + +static DvrSettings getDvrSettings(JNIEnv *env, jobject settings) { + DvrSettings dvrSettings; + jclass clazz = env->FindClass("android/media/tv/tuner/DvrSettings"); + uint32_t statusMask = + static_cast<uint32_t>(env->GetIntField( + settings, env->GetFieldID(clazz, "mStatusMask", "I"))); + uint32_t lowThreshold = + static_cast<uint32_t>(env->GetIntField( + settings, env->GetFieldID(clazz, "mLowThreshold", "I"))); + uint32_t highThreshold = + static_cast<uint32_t>(env->GetIntField( + settings, env->GetFieldID(clazz, "mHighThreshold", "I"))); + uint8_t packetSize = + static_cast<uint8_t>(env->GetIntField( + settings, env->GetFieldID(clazz, "mPacketSize", "I"))); + DataFormat dataFormat = + static_cast<DataFormat>(env->GetIntField( + settings, env->GetFieldID(clazz, "mDataFormat", "I"))); + DvrType type = + static_cast<DvrType>(env->GetIntField( + settings, env->GetFieldID(clazz, "mType", "I"))); + if (type == DvrType::RECORD) { + RecordSettings recordSettings { + .statusMask = static_cast<unsigned char>(statusMask), + .lowThreshold = lowThreshold, + .highThreshold = highThreshold, + .dataFormat = dataFormat, + .packetSize = packetSize, + }; + dvrSettings.record(recordSettings); + } else if (type == DvrType::PLAYBACK) { + PlaybackSettings PlaybackSettings { + .statusMask = statusMask, + .lowThreshold = lowThreshold, + .highThreshold = highThreshold, + .dataFormat = dataFormat, + .packetSize = packetSize, + }; + dvrSettings.playback(PlaybackSettings); + } + return dvrSettings; } static sp<IDvr> getDvr(JNIEnv *env, jobject dvr) { @@ -542,8 +615,100 @@ static jobject android_media_tv_Tuner_open_filter( return tuner->openFilter(filterType, bufferSize); } +static DemuxFilterSettings getFilterSettings( + JNIEnv *env, int type, int subtype, jobject filterSettingsObj) { + DemuxFilterSettings filterSettings; + // TODO: more setting types + jobject settingsObj = + env->GetObjectField( + filterSettingsObj, + env->GetFieldID( + env->FindClass("android/media/tv/tuner/FilterSettings"), + "mSettings", + "Landroid/media/tv/tuner/FilterSettings$Settings;")); + if (type == (int)DemuxFilterMainType::TS) { + // DemuxTsFilterSettings + jclass clazz = env->FindClass("android/media/tv/tuner/FilterSettings$TsFilterSettings"); + int tpid = env->GetIntField(filterSettingsObj, env->GetFieldID(clazz, "mTpid", "I")); + if (subtype == (int)DemuxTsFilterType::PES) { + // DemuxFilterPesDataSettings + jclass settingClazz = + env->FindClass("android/media/tv/tuner/FilterSettings$PesSettings"); + int streamId = env->GetIntField( + settingsObj, env->GetFieldID(settingClazz, "mStreamId", "I")); + bool isRaw = (bool)env->GetBooleanField( + settingsObj, env->GetFieldID(settingClazz, "mIsRaw", "Z")); + DemuxFilterPesDataSettings filterPesDataSettings { + .streamId = static_cast<uint16_t>(streamId), + .isRaw = isRaw, + }; + DemuxTsFilterSettings tsFilterSettings { + .tpid = static_cast<uint16_t>(tpid), + }; + tsFilterSettings.filterSettings.pesData(filterPesDataSettings); + filterSettings.ts(tsFilterSettings); + } + } + return filterSettings; +} + +static int copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jint offset, int size) { + ALOGD("copyData, size=%d, offset=%d", size, offset); + + int available = filter->mFilterMQ->availableToRead(); + ALOGD("copyData, available=%d", available); + size = std::min(size, available); + + jboolean isCopy; + jbyte *dst = env->GetByteArrayElements(buffer, &isCopy); + ALOGD("copyData, isCopy=%d", isCopy); + if (dst == nullptr) { + ALOGD("Failed to GetByteArrayElements"); + return 0; + } + + if (filter->mFilterMQ->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) { + env->ReleaseByteArrayElements(buffer, dst, 0); + filter->mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); + } else { + ALOGD("Failed to read FMQ"); + env->ReleaseByteArrayElements(buffer, dst, 0); + return 0; + } + return size; +} + +static int android_media_tv_Tuner_configure_filter( + JNIEnv *env, jobject filter, int type, int subtype, jobject settings) { + ALOGD("configure filter type=%d, subtype=%d", type, subtype); + sp<Filter> filterSp = getFilter(env, filter); + sp<IFilter> iFilterSp = filterSp->getIFilter(); + if (iFilterSp == NULL) { + ALOGD("Failed to configure filter: filter not found"); + return (int)Result::INVALID_STATE; + } + DemuxFilterSettings filterSettings = getFilterSettings(env, type, subtype, settings); + Result res = iFilterSp->configure(filterSettings); + MQDescriptorSync<uint8_t> filterMQDesc; + if (res == Result::SUCCESS && filterSp->mFilterMQ == NULL) { + Result getQueueDescResult = Result::UNKNOWN_ERROR; + iFilterSp->getQueueDesc( + [&](Result r, const MQDescriptorSync<uint8_t>& desc) { + filterMQDesc = desc; + getQueueDescResult = r; + ALOGD("getFilterQueueDesc"); + }); + if (getQueueDescResult == Result::SUCCESS) { + filterSp->mFilterMQ = std::make_unique<FilterMQ>(filterMQDesc, true); + EventFlag::createEventFlag( + filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag)); + } + } + return (int)res; +} + static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) { - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (filterSp == NULL) { ALOGD("Failed to start filter: filter not found"); return false; @@ -552,7 +717,7 @@ static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) { } static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) { - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (filterSp == NULL) { ALOGD("Failed to stop filter: filter not found"); return false; @@ -561,7 +726,7 @@ static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) { } static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) { - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (filterSp == NULL) { ALOGD("Failed to flush filter: filter not found"); return false; @@ -569,6 +734,16 @@ static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) { return filterSp->flush() == Result::SUCCESS; } +static int android_media_tv_Tuner_read_filter_fmq( + JNIEnv *env, jobject filter, jbyteArray buffer, jint offset, jint size) { + sp<Filter> filterSp = getFilter(env, filter); + if (filterSp == NULL) { + ALOGD("Failed to read filter FMQ: filter not found"); + return 0; + } + return copyData(env, filterSp, buffer, offset, size); +} + static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) { sp<JTuner> tuner = getTuner(env, thiz); return tuner->openDescrambler(); @@ -580,7 +755,7 @@ static bool android_media_tv_Tuner_add_pid( if (descramblerSp == NULL) { return false; } - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), filterSp); return result == Result::SUCCESS; } @@ -591,7 +766,7 @@ static bool android_media_tv_Tuner_remove_pid( if (descramblerSp == NULL) { return false; } - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), filterSp); return result == Result::SUCCESS; } @@ -603,7 +778,7 @@ static jobject android_media_tv_Tuner_open_dvr(JNIEnv *env, jobject thiz, jint t static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr); - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (dvrSp == NULL || filterSp == NULL) { return false; } @@ -613,7 +788,7 @@ static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobje static bool android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr); - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (dvrSp == NULL || filterSp == NULL) { return false; } @@ -621,6 +796,16 @@ static bool android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobje return result == Result::SUCCESS; } +static int android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) { + sp<IDvr> dvrSp = getDvr(env, dvr); + if (dvrSp == NULL) { + ALOGD("Failed to configure dvr: dvr not found"); + return (int)Result::INVALID_STATE; + } + Result result = dvrSp->configure(getDvrSettings(env, settings)); + return (int)result; +} + static bool android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) { sp<IDvr> dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { @@ -670,9 +855,12 @@ static const JNINativeMethod gTunerMethods[] = { }; static const JNINativeMethod gFilterMethods[] = { + { "nativeConfigureFilter", "(IILandroid/media/tv/tuner/FilterSettings;)I", + (void *)android_media_tv_Tuner_configure_filter }, { "nativeStartFilter", "()Z", (void *)android_media_tv_Tuner_start_filter }, { "nativeStopFilter", "()Z", (void *)android_media_tv_Tuner_stop_filter }, { "nativeFlushFilter", "()Z", (void *)android_media_tv_Tuner_flush_filter }, + { "nativeRead", "([BII)I", (void *)android_media_tv_Tuner_read_filter_fmq }, }; static const JNINativeMethod gDescramblerMethods[] = { @@ -687,6 +875,8 @@ static const JNINativeMethod gDvrMethods[] = { (void *)android_media_tv_Tuner_attach_filter }, { "nativeDetachFilter", "(Landroid/media/tv/tuner/Tuner$Filter;)Z", (void *)android_media_tv_Tuner_detach_filter }, + { "nativeConfigureDvr", "(Landroid/media/tv/tuner/DvrSettings;)I", + (void *)android_media_tv_Tuner_configure_dvr }, { "nativeStartDvr", "()Z", (void *)android_media_tv_Tuner_start_dvr }, { "nativeStopDvr", "()Z", (void *)android_media_tv_Tuner_stop_dvr }, { "nativeFlushDvr", "()Z", (void *)android_media_tv_Tuner_flush_dvr }, diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index f856791e2618..467acb8cdbdd 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -18,13 +18,18 @@ #define _ANDROID_MEDIA_TV_TUNER_H_ #include <android/hardware/tv/tuner/1.0/ITuner.h> +#include <fmq/MessageQueue.h> #include <unordered_map> #include <utils/RefBase.h> #include "jni.h" +using ::android::hardware::EventFlag; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::MessageQueue; using ::android::hardware::Return; using ::android::hardware::hidl_vec; +using ::android::hardware::kSynchronizedReadWrite; using ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent; using ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus; using ::android::hardware::tv::tuner::V1_0::DemuxFilterType; @@ -51,6 +56,8 @@ using ::android::hardware::tv::tuner::V1_0::LnbId; using ::android::hardware::tv::tuner::V1_0::PlaybackStatus; using ::android::hardware::tv::tuner::V1_0::RecordStatus; +using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; + namespace android { struct LnbCallback : public ILnbCallback { @@ -91,6 +98,17 @@ struct FrontendCallback : public IFrontendCallback { FrontendId mId; }; +struct Filter : public RefBase { + Filter(sp<IFilter> sp, jweak obj); + ~Filter(); + int close(); + sp<IFilter> getIFilter(); + sp<IFilter> mFilterSp; + std::unique_ptr<FilterMQ> mFilterMQ; + EventFlag* mFilterMQEventFlag; + jweak mFilterObj; +}; + struct JTuner : public RefBase { JTuner(JNIEnv *env, jobject thiz); sp<ITuner> getTunerService(); diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp index 79e4d8ae6e26..c8f0ff10ca3f 100644 --- a/media/jni/soundpool/StreamManager.cpp +++ b/media/jni/soundpool/StreamManager.cpp @@ -38,7 +38,7 @@ static constexpr bool kStealActiveStream_OldestFirst = true; // kPlayOnCallingThread = true prior to R. // Changing to false means calls to play() are almost instantaneous instead of taking around // ~10ms to launch the AudioTrack. It is perhaps 100x faster. -static constexpr bool kPlayOnCallingThread = true; +static constexpr bool kPlayOnCallingThread = false; // Amount of time for a StreamManager thread to wait before closing. static constexpr int64_t kWaitTimeBeforeCloseNs = 9 * NANOS_PER_SECOND; @@ -170,7 +170,6 @@ int32_t StreamManager::queueForPlay(const std::shared_ptr<Sound> &sound, if (stream->getSoundID() == soundID) { ALOGV("%s: found soundID %d in restart queue", __func__, soundID); newStream = stream; - fromAvailableQueue = false; break; } else if (newStream == nullptr) { ALOGV("%s: found stream in restart queue", __func__); diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java index 45430197fdd8..291cdd5ea3d8 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java @@ -35,6 +35,7 @@ import android.view.ViewStub; import androidx.recyclerview.widget.GridLayoutManager; +import com.android.internal.widget.LockPatternUtils; import com.android.systemui.R; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.dagger.qualifiers.MainResources; @@ -135,8 +136,9 @@ public class FullscreenUserSwitcher { /* isAddUser= */ false, /* isForeground= */ true); - // If the initial user has trusted device, display the unlock dialog on the keyguard. - if (hasTrustedDevice(initialUser)) { + // If the initial user has screen lock and trusted device, display the unlock dialog on the + // keyguard. + if (hasScreenLock(initialUser) && hasTrustedDevice(initialUser)) { mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser, mOnHideListener); } else { @@ -178,7 +180,7 @@ public class FullscreenUserSwitcher { */ private void onUserSelected(UserGridRecyclerView.UserRecord record) { mSelectedUser = record; - if (hasTrustedDevice(record.mInfo.id)) { + if (hasScreenLock(record.mInfo.id) && hasTrustedDevice(record.mInfo.id)) { mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, mOnHideListener); return; } @@ -216,6 +218,12 @@ public class FullscreenUserSwitcher { } + private boolean hasScreenLock(int uid) { + LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); + return lockPatternUtils.getCredentialTypeForUser(uid) + != LockPatternUtils.CREDENTIAL_TYPE_NONE; + } + private boolean hasTrustedDevice(int uid) { if (mEnrollmentManager == null) { // car service not ready, so it cannot be available. return false; diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java index 96aee512c090..a2bd210b67a6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java @@ -155,8 +155,8 @@ public class A2dpProfile implements LocalBluetoothProfile { public boolean disconnect(BluetoothDevice device) { if (mService == null) return false; // Downgrade priority as user is disconnecting the headset. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -179,23 +179,29 @@ public class A2dpProfile implements LocalBluetoothProfile { } public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + if (mService == null) { + return false; + } + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; - return mService.getPriority(device); + if (mService == null) { + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + } + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { - if (mService == null) return; + if (mService == null) { + return; + } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } boolean isA2dpPlaying() { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java index 55765dd40d36..9c896c80b409 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java @@ -124,8 +124,8 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { return false; } // Downgrade priority as user is disconnecting the headset. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -141,14 +141,14 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { @@ -156,11 +156,11 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java index 9f7b7181b19f..560cb3b9b5b4 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java @@ -120,8 +120,8 @@ public class HeadsetProfile implements LocalBluetoothProfile { return false; } // Downgrade priority as user is disconnecting the headset. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -165,14 +165,14 @@ public class HeadsetProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { @@ -180,11 +180,11 @@ public class HeadsetProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java index ebaeb742b198..58655a2b930a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java @@ -153,8 +153,8 @@ public class HearingAidProfile implements LocalBluetoothProfile { public boolean disconnect(BluetoothDevice device) { if (mService == null) return false; // Downgrade priority as user is disconnecting the hearing aid. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -177,23 +177,29 @@ public class HearingAidProfile implements LocalBluetoothProfile { } public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + if (mService == null) { + return false; + } + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; - return mService.getPriority(device); + if (mService == null) { + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + } + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { - if (mService == null) return; + if (mService == null) { + return; + } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java index 860b77d1ebcd..a372e23654e0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java @@ -135,8 +135,8 @@ final class HfpClientProfile implements LocalBluetoothProfile { return false; } // Downgrade priority as user is disconnecting the headset. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -154,15 +154,15 @@ final class HfpClientProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } @Override public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } @Override @@ -171,11 +171,11 @@ final class HfpClientProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java index 6d874ab2be9b..975a1e67af5b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java @@ -116,23 +116,27 @@ public class HidProfile implements LocalBluetoothProfile { } public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; - return mService.getPriority(device) != BluetoothProfile.PRIORITY_OFF; + if (mService == null) { + return false; + } + return mService.getConnectionPolicy(device) != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; - return mService.getPriority(device); + if (mService == null) { + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + } + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { if (mService == null) return; if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java index d4dda329fa63..95139a1bfab9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java @@ -123,8 +123,8 @@ public final class MapClientProfile implements LocalBluetoothProfile { return false; } // Downgrade priority as user is disconnecting. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -140,14 +140,14 @@ public final class MapClientProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { @@ -155,11 +155,11 @@ public final class MapClientProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java index b2a9a6a28231..31a0eea56b42 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java @@ -119,8 +119,8 @@ public class MapProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -136,14 +136,14 @@ public class MapProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { @@ -151,11 +151,11 @@ public class MapProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java index e1e5dbe29a1a..8e3f3edcef10 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java @@ -57,7 +57,7 @@ final class OppProfile implements LocalBluetoothProfile { } public int getPreferred(BluetoothDevice device) { - return BluetoothProfile.PRIORITY_OFF; // Settings app doesn't handle OPP + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; // Settings app doesn't handle OPP } public void setPreferred(BluetoothDevice device, boolean preferred) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java index a2da4fb30e39..4ea0df621bea 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java @@ -151,14 +151,14 @@ public final class PbapClientProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { @@ -166,11 +166,11 @@ public final class PbapClientProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java index 9b733f2e0e50..0ca4d6195a32 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java @@ -119,8 +119,8 @@ final class SapProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -136,14 +136,14 @@ final class SapProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { @@ -151,11 +151,11 @@ final class SapProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index b0bdf1dd8594..328bfb281992 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -188,6 +188,8 @@ public class AccessPoint implements Comparable<AccessPoint> { static final String KEY_SUBSCRIPTION_EXPIRATION_TIME_IN_MILLIS = "key_subscription_expiration_time_in_millis"; static final String KEY_PASSPOINT_CONFIGURATION_VERSION = "key_passpoint_configuration_version"; + static final String KEY_IS_PSK_SAE_TRANSITION_MODE = "key_is_psk_sae_transition_mode"; + static final String KEY_IS_OWE_TRANSITION_MODE = "key_is_owe_transition_mode"; static final AtomicInteger sLastId = new AtomicInteger(0); /* @@ -202,15 +204,12 @@ public class AccessPoint implements Comparable<AccessPoint> { public static final int SECURITY_OWE = 4; public static final int SECURITY_SAE = 5; public static final int SECURITY_EAP_SUITE_B = 6; - public static final int SECURITY_PSK_SAE_TRANSITION = 7; - public static final int SECURITY_OWE_TRANSITION = 8; - public static final int SECURITY_MAX_VAL = 9; // Has to be the last + public static final int SECURITY_MAX_VAL = 7; // Has to be the last private static final int PSK_UNKNOWN = 0; private static final int PSK_WPA = 1; private static final int PSK_WPA2 = 2; private static final int PSK_WPA_WPA2 = 3; - private static final int PSK_SAE = 4; private static final int EAP_UNKNOWN = 0; private static final int EAP_WPA = 1; // WPA-EAP @@ -274,6 +273,9 @@ public class AccessPoint implements Comparable<AccessPoint> { private String mOsuFailure; private boolean mOsuProvisioningComplete = false; + private boolean mIsPskSaeTransitionMode = false; + private boolean mIsOweTransitionMode = false; + /** * The EAP type {@link WifiEnterpriseConfig.Eap} associated with this AP if it is a carrier AP. */ @@ -344,6 +346,13 @@ public class AccessPoint implements Comparable<AccessPoint> { if (savedState.containsKey(KEY_PASSPOINT_CONFIGURATION_VERSION)) { mPasspointConfigurationVersion = savedState.getInt(KEY_PASSPOINT_CONFIGURATION_VERSION); } + if (savedState.containsKey(KEY_IS_PSK_SAE_TRANSITION_MODE)) { + mIsPskSaeTransitionMode = savedState.getBoolean(KEY_IS_PSK_SAE_TRANSITION_MODE); + } + if (savedState.containsKey(KEY_IS_OWE_TRANSITION_MODE)) { + mIsOweTransitionMode = savedState.getBoolean(KEY_IS_OWE_TRANSITION_MODE); + } + update(mConfig, mInfo, mNetworkInfo); // Calculate required fields @@ -675,8 +684,15 @@ public class AccessPoint implements Comparable<AccessPoint> { return oldMetering == mIsScoredNetworkMetered; } - public static String getKey(ScanResult result) { - return getKey(result.SSID, result.BSSID, getSecurity(result)); + /** + * Generates an AccessPoint key for a given scan result + * + * @param context + * @param result Scan result + * @return AccessPoint key + */ + public static String getKey(Context context, ScanResult result) { + return getKey(result.SSID, result.BSSID, getSecurity(context, result)); } /** @@ -734,7 +750,42 @@ public class AccessPoint implements Comparable<AccessPoint> { * Determines if the other AccessPoint represents the same network as this AccessPoint */ public boolean matches(AccessPoint other) { - return getKey().equals(other.getKey()); + if (isPasspoint() || isPasspointConfig() || isOsuProvider()) { + return getKey().equals(other.getKey()); + } + + if (!isSameSsidOrBssid(other)) { + return false; + } + + final int otherApSecurity = other.getSecurity(); + if (mIsPskSaeTransitionMode) { + if (otherApSecurity == SECURITY_SAE && getWifiManager().isWpa3SaeSupported()) { + return true; + } else if (otherApSecurity == SECURITY_PSK) { + return true; + } + } else { + if ((security == SECURITY_SAE || security == SECURITY_PSK) + && other.isPskSaeTransitionMode()) { + return true; + } + } + + if (mIsOweTransitionMode) { + if (otherApSecurity == SECURITY_OWE && getWifiManager().isEnhancedOpenSupported()) { + return true; + } else if (otherApSecurity == SECURITY_NONE) { + return true; + } + } else { + if ((security == SECURITY_OWE || security == SECURITY_NONE) + && other.isOweTransitionMode()) { + return true; + } + } + + return security == other.getSecurity(); } public boolean matches(WifiConfiguration config) { @@ -748,18 +799,77 @@ public class AccessPoint implements Comparable<AccessPoint> { } final int configSecurity = getSecurity(config); - final WifiManager wifiManager = getWifiManager(); - switch (security) { - case SECURITY_PSK_SAE_TRANSITION: - return configSecurity == SECURITY_PSK - || (wifiManager.isWpa3SaeSupported() && configSecurity == SECURITY_SAE); - case SECURITY_OWE_TRANSITION: - return configSecurity == SECURITY_NONE - || (wifiManager.isEnhancedOpenSupported() - && configSecurity == SECURITY_OWE); - default: - return security == configSecurity; + if (mIsPskSaeTransitionMode) { + if (configSecurity == SECURITY_SAE && getWifiManager().isWpa3SaeSupported()) { + return true; + } else if (configSecurity == SECURITY_PSK) { + return true; + } + } + + if (mIsOweTransitionMode) { + if (configSecurity == SECURITY_OWE && getWifiManager().isEnhancedOpenSupported()) { + return true; + } else if (configSecurity == SECURITY_NONE) { + return true; + } } + + return security == getSecurity(config); + } + + private boolean matches(WifiConfiguration config, WifiInfo wifiInfo) { + if (config == null || wifiInfo == null) { + return false; + } + if (!config.isPasspoint() && !isSameSsidOrBssid(wifiInfo)) { + return false; + } + return matches(config); + } + + @VisibleForTesting + boolean matches(ScanResult scanResult) { + if (scanResult == null) { + return false; + } + if (isPasspoint() || isOsuProvider()) { + throw new IllegalStateException("Should not matches a Passpoint by ScanResult"); + } + + if (!isSameSsidOrBssid(scanResult)) { + return false; + } + + if (mIsPskSaeTransitionMode) { + if (scanResult.capabilities.contains("SAE") + && getWifiManager().isWpa3SaeSupported()) { + return true; + } else if (scanResult.capabilities.contains("PSK")) { + return true; + } + } else { + if ((security == SECURITY_SAE || security == SECURITY_PSK) + && AccessPoint.isPskSaeTransitionMode(scanResult)) { + return true; + } + } + + if (mIsOweTransitionMode) { + final int scanResultSccurity = getSecurity(mContext, scanResult); + if (scanResultSccurity == SECURITY_OWE && getWifiManager().isEnhancedOpenSupported()) { + return true; + } else if (scanResultSccurity == SECURITY_NONE) { + return true; + } + } else { + if ((security == SECURITY_OWE || security == SECURITY_NONE) + && AccessPoint.isOweTransitionMode(scanResult)) { + return true; + } + } + + return security == getSecurity(mContext, scanResult); } public WifiConfiguration getConfig() { @@ -846,14 +956,17 @@ public class AccessPoint implements Comparable<AccessPoint> { if (bestResult != null) { ssid = bestResult.SSID; bssid = bestResult.BSSID; - security = getSecurity(bestResult); - if (security == SECURITY_PSK || security == SECURITY_SAE - || security == SECURITY_PSK_SAE_TRANSITION) { + security = getSecurity(mContext, bestResult); + if (security == SECURITY_PSK || security == SECURITY_SAE) { pskType = getPskType(bestResult); } if (security == SECURITY_EAP) { mEapType = getEapType(bestResult); } + + mIsPskSaeTransitionMode = AccessPoint.isPskSaeTransitionMode(bestResult); + mIsOweTransitionMode = AccessPoint.isOweTransitionMode(bestResult); + mIsCarrierAp = bestResult.isCarrierAp; mCarrierApEapType = bestResult.carrierApEapType; mCarrierName = bestResult.carrierName; @@ -886,6 +999,12 @@ public class AccessPoint implements Comparable<AccessPoint> { return concise ? context.getString(R.string.wifi_security_short_eap) : context.getString(R.string.wifi_security_eap); } + + if (mIsPskSaeTransitionMode) { + return concise ? context.getString(R.string.wifi_security_short_psk_sae) : + context.getString(R.string.wifi_security_psk_sae); + } + switch(security) { case SECURITY_EAP: switch (mEapType) { @@ -925,20 +1044,8 @@ public class AccessPoint implements Comparable<AccessPoint> { return concise ? context.getString(R.string.wifi_security_short_wep) : context.getString(R.string.wifi_security_wep); case SECURITY_SAE: - case SECURITY_PSK_SAE_TRANSITION: - if (pskType == PSK_SAE) { - return concise ? context.getString(R.string.wifi_security_short_psk_sae) : - context.getString(R.string.wifi_security_psk_sae); - } else { - return concise ? context.getString(R.string.wifi_security_short_sae) : - context.getString(R.string.wifi_security_sae); - } - case SECURITY_OWE_TRANSITION: - if (mConfig != null && getSecurity(mConfig) == SECURITY_OWE) { - return concise ? context.getString(R.string.wifi_security_short_owe) : - context.getString(R.string.wifi_security_owe); - } - return concise ? "" : context.getString(R.string.wifi_security_none); + return concise ? context.getString(R.string.wifi_security_short_sae) : + context.getString(R.string.wifi_security_sae); case SECURITY_OWE: return concise ? context.getString(R.string.wifi_security_short_owe) : context.getString(R.string.wifi_security_owe); @@ -1250,7 +1357,7 @@ public class AccessPoint implements Comparable<AccessPoint> { if (networkId != WifiConfiguration.INVALID_NETWORK_ID) { return networkId == info.getNetworkId(); } else if (config != null) { - return isKeyEqual(getKey(config)); + return matches(config, info); } else { // Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID. // (Note that we only do this if the WifiConfiguration explicitly equals INVALID). @@ -1322,43 +1429,14 @@ public class AccessPoint implements Comparable<AccessPoint> { savedState.putLong(KEY_SUBSCRIPTION_EXPIRATION_TIME_IN_MILLIS, mSubscriptionExpirationTimeInMillis); savedState.putInt(KEY_PASSPOINT_CONFIGURATION_VERSION, mPasspointConfigurationVersion); + savedState.putBoolean(KEY_IS_PSK_SAE_TRANSITION_MODE, mIsPskSaeTransitionMode); + savedState.putBoolean(KEY_IS_OWE_TRANSITION_MODE, mIsOweTransitionMode); } public void setListener(AccessPointListener listener) { mAccessPointListener = listener; } - private static final String sPskSuffix = "," + String.valueOf(SECURITY_PSK); - private static final String sSaeSuffix = "," + String.valueOf(SECURITY_SAE); - private static final String sPskSaeSuffix = "," + String.valueOf(SECURITY_PSK_SAE_TRANSITION); - private static final String sOweSuffix = "," + String.valueOf(SECURITY_OWE); - private static final String sOpenSuffix = "," + String.valueOf(SECURITY_NONE); - private static final String sOweTransSuffix = "," + String.valueOf(SECURITY_OWE_TRANSITION); - - private boolean isKeyEqual(String compareTo) { - if (mKey == null) { - return false; - } - - if (compareTo.endsWith(sPskSuffix) || compareTo.endsWith(sSaeSuffix)) { - if (mKey.endsWith(sPskSaeSuffix)) { - // Special handling for PSK-SAE transition mode. If the AP has advertised both, - // we compare the key with both PSK and SAE for a match. - return TextUtils.equals(mKey.substring(0, mKey.lastIndexOf(',')), - compareTo.substring(0, compareTo.lastIndexOf(','))); - } - } - if (compareTo.endsWith(sOpenSuffix) || compareTo.endsWith(sOweSuffix)) { - if (mKey.endsWith(sOweTransSuffix)) { - // Special handling for OWE/Open networks. If AP advertises OWE in transition mode - // and we have an Open network saved, allow this connection to be established. - return TextUtils.equals(mKey.substring(0, mKey.lastIndexOf(',')), - compareTo.substring(0, compareTo.lastIndexOf(','))); - } - } - return mKey.equals(compareTo); - } - /** * Sets {@link #mScanResults} to the given collection and updates info based on the best RSSI * scan result. @@ -1375,11 +1453,10 @@ public class AccessPoint implements Comparable<AccessPoint> { // Passpoint networks are not bound to a specific SSID/BSSID, so skip this for passpoint. if (mKey != null && !isPasspoint() && !isOsuProvider()) { for (ScanResult result : scanResults) { - String scanResultKey = AccessPoint.getKey(result); - if (!isKeyEqual(scanResultKey)) { + if (!matches(result)) { Log.d(TAG, String.format( - "ScanResult %s\nkey of %s did not match current AP key %s", - result, scanResultKey, mKey)); + "ScanResult %s\nkey of %s did not match current AP key %s", + result, getKey(mContext, result), mKey)); return; } } @@ -1653,11 +1730,8 @@ public class AccessPoint implements Comparable<AccessPoint> { private static int getPskType(ScanResult result) { boolean wpa = result.capabilities.contains("WPA-PSK"); boolean wpa2 = result.capabilities.contains("RSN-PSK"); - boolean wpa3TransitionMode = result.capabilities.contains("PSK+SAE"); boolean wpa3 = result.capabilities.contains("RSN-SAE"); - if (wpa3TransitionMode) { - return PSK_SAE; - } else if (wpa2 && wpa) { + if (wpa2 && wpa) { return PSK_WPA_WPA2; } else if (wpa2) { return PSK_WPA2; @@ -1684,22 +1758,37 @@ public class AccessPoint implements Comparable<AccessPoint> { return EAP_UNKNOWN; } - private static int getSecurity(ScanResult result) { - if (result.capabilities.contains("WEP")) { + private static int getSecurity(Context context, ScanResult result) { + final boolean isWep = result.capabilities.contains("WEP"); + final boolean isSae = result.capabilities.contains("SAE"); + final boolean isPsk = result.capabilities.contains("PSK"); + final boolean isEapSuiteB192 = result.capabilities.contains("EAP_SUITE_B_192"); + final boolean isEap = result.capabilities.contains("EAP"); + final boolean isOwe = result.capabilities.contains("OWE"); + final boolean isOweTransition = result.capabilities.contains("OWE_TRANSITION"); + + if (isSae && isPsk) { + final WifiManager wifiManager = (WifiManager) + context.getSystemService(Context.WIFI_SERVICE); + return wifiManager.isWpa3SaeSupported() ? SECURITY_SAE : SECURITY_PSK; + } + if (isOweTransition) { + final WifiManager wifiManager = (WifiManager) + context.getSystemService(Context.WIFI_SERVICE); + return wifiManager.isEnhancedOpenSupported() ? SECURITY_OWE : SECURITY_NONE; + } + + if (isWep) { return SECURITY_WEP; - } else if (result.capabilities.contains("PSK+SAE")) { - return SECURITY_PSK_SAE_TRANSITION; - } else if (result.capabilities.contains("SAE")) { + } else if (isSae) { return SECURITY_SAE; - } else if (result.capabilities.contains("PSK")) { + } else if (isPsk) { return SECURITY_PSK; - } else if (result.capabilities.contains("EAP_SUITE_B_192")) { + } else if (isEapSuiteB192) { return SECURITY_EAP_SUITE_B; - } else if (result.capabilities.contains("EAP")) { + } else if (isEap) { return SECURITY_EAP; - } else if (result.capabilities.contains("OWE_TRANSITION")) { - return SECURITY_OWE_TRANSITION; - } else if (result.capabilities.contains("OWE")) { + } else if (isOwe) { return SECURITY_OWE; } return SECURITY_NONE; @@ -1745,10 +1834,6 @@ public class AccessPoint implements Comparable<AccessPoint> { return "SUITE_B"; } else if (security == SECURITY_OWE) { return "OWE"; - } else if (security == SECURITY_PSK_SAE_TRANSITION) { - return "PSK+SAE"; - } else if (security == SECURITY_OWE_TRANSITION) { - return "OWE_TRANSITION"; } return "NONE"; } @@ -1776,8 +1861,7 @@ public class AccessPoint implements Comparable<AccessPoint> { * Return true if this is an open network AccessPoint. */ public boolean isOpenNetwork() { - return security == SECURITY_NONE || security == SECURITY_OWE - || security == SECURITY_OWE_TRANSITION; + return security == SECURITY_NONE || security == SECURITY_OWE; } /** @@ -1926,4 +2010,61 @@ public class AccessPoint implements Comparable<AccessPoint> { } } } + + public boolean isPskSaeTransitionMode() { + return mIsPskSaeTransitionMode; + } + + public boolean isOweTransitionMode() { + return mIsOweTransitionMode; + } + + private static boolean isPskSaeTransitionMode(ScanResult scanResult) { + return scanResult.capabilities.contains("PSK") + && scanResult.capabilities.contains("SAE"); + } + + private static boolean isOweTransitionMode(ScanResult scanResult) { + return scanResult.capabilities.contains("OWE_TRANSITION"); + } + + private boolean isSameSsidOrBssid(ScanResult scanResult) { + if (scanResult == null) { + return false; + } + + if (TextUtils.equals(ssid, scanResult.SSID)) { + return true; + } else if (scanResult.BSSID != null && TextUtils.equals(bssid, scanResult.BSSID)) { + return true; + } + return false; + } + + private boolean isSameSsidOrBssid(WifiInfo wifiInfo) { + if (wifiInfo == null) { + return false; + } + + if (TextUtils.equals(ssid, removeDoubleQuotes(wifiInfo.getSSID()))) { + return true; + } else if (wifiInfo.getBSSID() != null && TextUtils.equals(bssid, wifiInfo.getBSSID())) { + return true; + } + return false; + } + + private boolean isSameSsidOrBssid(AccessPoint accessPoint) { + if (accessPoint == null) { + return false; + } + + if (TextUtils.equals(ssid, accessPoint.getSsid())) { + return true; + } else if (accessPoint.getBssid() != null + && TextUtils.equals(bssid, accessPoint.getBssid())) { + return true; + } + return false; + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java index dae546497aba..6269a717b333 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java @@ -201,8 +201,7 @@ public class AccessPointPreference extends Preference { return; } if ((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) - && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE) - && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE_TRANSITION)) { + && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) { mFrictionSld.setState(STATE_SECURED); } else if (mAccessPoint.isMetered()) { mFrictionSld.setState(STATE_METERED); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index 23b16e811606..ba6a8ea31987 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -70,8 +70,10 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; /** * Tracks saved or available wifi networks and their state. @@ -475,7 +477,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro continue; } - String apKey = AccessPoint.getKey(result); + String apKey = AccessPoint.getKey(mContext, result); List<ScanResult> resultList; if (scanResultsByApKey.containsKey(apKey)) { resultList = scanResultsByApKey.get(apKey); @@ -547,14 +549,6 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro private void updateAccessPoints(final List<ScanResult> newScanResults, List<WifiConfiguration> configs) { - // Map configs and scan results necessary to make AccessPoints - final Map<String, WifiConfiguration> configsByKey = new ArrayMap(configs.size()); - if (configs != null) { - for (WifiConfiguration config : configs) { - configsByKey.put(AccessPoint.getKey(config), config); - } - } - WifiConfiguration connectionConfig = null; if (mLastInfo != null) { connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId(), configs); @@ -586,7 +580,26 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro getCachedOrCreate(entry.getValue(), cachedAccessPoints); // Update the matching config if there is one, to populate saved network info - accessPoint.update(configsByKey.get(entry.getKey())); + final List<WifiConfiguration> matchedConfigs = configs.stream() + .filter(config -> accessPoint.matches(config)) + .collect(Collectors.toList()); + + final int matchedConfigCount = matchedConfigs.size(); + if (matchedConfigCount == 0) { + accessPoint.update(null); + } else if (matchedConfigCount == 1) { + accessPoint.update(matchedConfigs.get(0)); + } else { + // We may have 2 matched configured WifiCongiguration if the AccessPoint is + // of PSK/SAE transition mode or open/OWE transition mode. + Optional<WifiConfiguration> preferredConfig = matchedConfigs.stream() + .filter(config -> isSaeOrOwe(config)).findFirst(); + if (preferredConfig.isPresent()) { + accessPoint.update(preferredConfig.get()); + } else { + accessPoint.update(matchedConfigs.get(0)); + } + } accessPoints.add(accessPoint); } @@ -652,6 +665,11 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro conditionallyNotifyListeners(); } + private static boolean isSaeOrOwe(WifiConfiguration config) { + final int security = AccessPoint.getSecurity(config); + return security == AccessPoint.SECURITY_SAE || security == AccessPoint.SECURITY_OWE; + } + @VisibleForTesting List<AccessPoint> updatePasspointAccessPoints( List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans, @@ -700,7 +718,8 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro private AccessPoint getCachedOrCreate( List<ScanResult> scanResults, List<AccessPoint> cache) { - AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(scanResults.get(0))); + AccessPoint accessPoint = getCachedByKey(cache, + AccessPoint.getKey(mContext, scanResults.get(0))); if (accessPoint == null) { accessPoint = new AccessPoint(mContext, scanResults); } else { diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index 7b1c3825fcc6..325366ea6e40 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -39,6 +39,7 @@ import android.net.ScoredNetwork; import android.net.WifiKey; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiEnterpriseConfig; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -1273,7 +1274,7 @@ public class AccessPointTest { @Test public void testGetKey_matchesKeysCorrectly() { AccessPoint ap = new AccessPoint(mContext, mScanResults); - assertThat(ap.getKey()).isEqualTo(AccessPoint.getKey(mScanResults.get(0))); + assertThat(ap.getKey()).isEqualTo(AccessPoint.getKey(mContext, mScanResults.get(0))); WifiConfiguration spyConfig = spy(new WifiConfiguration()); when(spyConfig.isPasspoint()).thenReturn(true); @@ -1295,6 +1296,44 @@ public class AccessPointTest { } /** + * Test that getKey returns a key of SAE type for a PSK/SAE transition mode ScanResult. + */ + @Test + public void testGetKey_supportSaeTransitionMode_shouldGetSaeKey() { + ScanResult scanResult = createScanResult(TEST_SSID, TEST_BSSID, DEFAULT_RSSI); + scanResult.capabilities = + "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]"; + when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true); + when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager); + StringBuilder key = new StringBuilder(); + key.append(AccessPoint.KEY_PREFIX_AP); + key.append(TEST_SSID); + key.append(','); + key.append(AccessPoint.SECURITY_SAE); + + assertThat(AccessPoint.getKey(mMockContext, scanResult)).isEqualTo(key.toString()); + } + + /** + * Test that getKey returns a key of PSK type for a PSK/SAE transition mode ScanResult. + */ + @Test + public void testGetKey_notSupportSaeTransitionMode_shouldGetPskKey() { + ScanResult scanResult = createScanResult(TEST_SSID, TEST_BSSID, DEFAULT_RSSI); + scanResult.capabilities = + "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]"; + when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false); + when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager); + StringBuilder key = new StringBuilder(); + key.append(AccessPoint.KEY_PREFIX_AP); + key.append(TEST_SSID); + key.append(','); + key.append(AccessPoint.SECURITY_PSK); + + assertThat(AccessPoint.getKey(mMockContext, scanResult)).isEqualTo(key.toString()); + } + + /** * Verifies that the Passpoint AccessPoint constructor creates AccessPoints whose isPasspoint() * returns true. */ @@ -1537,12 +1576,120 @@ public class AccessPointTest { bundle.putInt("key_security", i); ap = new AccessPoint(InstrumentationRegistry.getTargetContext(), bundle); - if (i == AccessPoint.SECURITY_NONE || i == AccessPoint.SECURITY_OWE - || i == AccessPoint.SECURITY_OWE_TRANSITION) { + if (i == AccessPoint.SECURITY_NONE || i == AccessPoint.SECURITY_OWE) { assertThat(ap.isOpenNetwork()).isTrue(); } else { assertThat(ap.isOpenNetwork()).isFalse(); } } } + + /** + * Verifies that matches(AccessPoint other) matches a PSK/SAE transition mode AP to a PSK or a + * SAE AP. + */ + @Test + public void testMatches1_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() { + when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager); + when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true); + AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp(); + + // Transition mode AP matches a SAE AP. + AccessPoint saeAccessPoint = new TestAccessPointBuilder(mContext) + .setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID)) + .setSecurity(AccessPoint.SECURITY_SAE) + .build(); + assertThat(pskSaeTransitionModeAp.matches(saeAccessPoint)).isTrue(); + + // Transition mode AP matches a PSK AP. + AccessPoint pskAccessPoint = new TestAccessPointBuilder(mContext) + .setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID)) + .setSecurity(AccessPoint.SECURITY_PSK) + .build(); + + assertThat(pskSaeTransitionModeAp.matches(pskAccessPoint)).isTrue(); + + // Transition mode AP does not match a SAE AP if the device does not support SAE. + when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false); + pskSaeTransitionModeAp = getPskSaeTransitionModeAp(); + saeAccessPoint = new TestAccessPointBuilder(mContext) + .setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID)) + .setSecurity(AccessPoint.SECURITY_SAE) + .build(); + + assertThat(pskSaeTransitionModeAp.matches(saeAccessPoint)).isFalse(); + } + + /** + * Verifies that matches(WifiConfiguration config) matches a PSK/SAE transition mode AP to a PSK + * or a SAE WifiConfiguration. + */ + @Test + public void testMatches2_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() { + when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager); + when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true); + AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp(); + + // Transition mode AP matches a SAE WifiConfiguration. + WifiConfiguration saeConfig = new WifiConfiguration(); + saeConfig.SSID = TEST_SSID; + saeConfig.allowedKeyManagement.set(KeyMgmt.SAE); + + assertThat(pskSaeTransitionModeAp.matches(saeConfig)).isTrue(); + + // Transition mode AP matches a PSK WifiConfiguration. + WifiConfiguration pskConfig = new WifiConfiguration(); + pskConfig.SSID = TEST_SSID; + pskConfig.allowedKeyManagement.set(KeyMgmt.WPA_PSK); + + assertThat(pskSaeTransitionModeAp.matches(pskConfig)).isTrue(); + + // Transition mode AP does not matches a SAE WifiConfiguration if the device does not + // support SAE. + when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false); + pskSaeTransitionModeAp = getPskSaeTransitionModeAp(); + + assertThat(pskSaeTransitionModeAp.matches(saeConfig)).isFalse(); + } + + /** + * Verifies that matches(ScanResult scanResult) matches a PSK/SAE transition mode AP to a PSK + * or a SAE ScanResult. + */ + @Test + public void testMatches3_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() { + when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager); + when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true); + AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp(); + + // Transition mode AP matches a SAE ScanResult. + ScanResult saeScanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID), + TEST_BSSID, DEFAULT_RSSI); + saeScanResult.capabilities = "[SAE-CCMP][ESS][WPS]"; + + assertThat(pskSaeTransitionModeAp.matches(saeScanResult)).isTrue(); + + // Transition mode AP matches a PSK ScanResult. + ScanResult pskScanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID), + TEST_BSSID, DEFAULT_RSSI); + pskScanResult.capabilities = "[RSN-PSK-CCMP][ESS][WPS]"; + + assertThat(pskSaeTransitionModeAp.matches(pskScanResult)).isTrue(); + + // Transition mode AP does not matches a SAE ScanResult if the device does not support SAE. + when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false); + pskSaeTransitionModeAp = getPskSaeTransitionModeAp(); + + assertThat(pskSaeTransitionModeAp.matches(saeScanResult)).isFalse(); + } + + private AccessPoint getPskSaeTransitionModeAp() { + ScanResult scanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID), + TEST_BSSID, DEFAULT_RSSI); + scanResult.capabilities = + "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]"; + return new TestAccessPointBuilder(mMockContext) + .setScanResults(new ArrayList<ScanResult>(Arrays.asList(scanResult))) + .build(); + } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 4731e6894baf..086b20facb46 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -62,6 +62,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -766,6 +768,23 @@ final class SettingsState { } } catch (Throwable t) { Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", t); + if (t instanceof IOException) { + // we failed to create a directory, so log the permissions and existence + // state for the settings file and directory + logSettingsDirectoryInformation(destination.getBaseFile()); + if (t.getMessage().contains("Couldn't create directory")) { + // attempt to create the directory with Files.createDirectories, which + // throws more informative errors than File.mkdirs. + Path parentPath = destination.getBaseFile().getParentFile().toPath(); + try { + Files.createDirectories(parentPath); + Slog.i(LOG_TAG, "Successfully created " + parentPath); + } catch (Throwable t2) { + Slog.e(LOG_TAG, "Failed to write " + parentPath + + " with Files.writeDirectories", t2); + } + } + } destination.failWrite(out); } finally { IoUtils.closeQuietly(out); @@ -779,6 +798,33 @@ final class SettingsState { } } + private static void logSettingsDirectoryInformation(File settingsFile) { + File parent = settingsFile.getParentFile(); + Slog.i(LOG_TAG, "directory info for directory/file " + settingsFile + + " with stacktrace ", new Exception()); + File ancestorDir = parent; + while (ancestorDir != null) { + if (!ancestorDir.exists()) { + Slog.i(LOG_TAG, "ancestor directory " + ancestorDir + + " does not exist"); + ancestorDir = ancestorDir.getParentFile(); + } else { + Slog.i(LOG_TAG, "ancestor directory " + ancestorDir + + " exists"); + Slog.i(LOG_TAG, "ancestor directory " + ancestorDir + + " permissions: r: " + ancestorDir.canRead() + " w: " + + ancestorDir.canWrite() + " x: " + ancestorDir.canExecute()); + File ancestorParent = ancestorDir.getParentFile(); + if (ancestorParent != null) { + Slog.i(LOG_TAG, "ancestor's parent directory " + ancestorParent + + " permissions: r: " + ancestorParent.canRead() + " w: " + + ancestorParent.canWrite() + " x: " + ancestorParent.canExecute()); + } + break; + } + } + } + static void writeSingleSetting(int version, XmlSerializer serializer, String id, String name, String value, String defaultValue, String packageName, String tag, boolean defaultSysSet) throws IOException { @@ -853,6 +899,7 @@ final class SettingsState { in = new AtomicFile(mStatePersistFile).openRead(); } catch (FileNotFoundException fnfe) { Slog.i(LOG_TAG, "No settings state " + mStatePersistFile); + logSettingsDirectoryInformation(mStatePersistFile); addHistoricalOperationLocked(HISTORICAL_OPERATION_INITIALIZE, null); return; } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 7f1d5280ab77..b89f1412c6a6 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -221,6 +221,9 @@ <!-- Permission required for CTS test - CarModeInCallServiceTest --> <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"/> + <!-- Permission requried for CTS test - CellBroadcastIntentsTest --> + <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"/> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 0c582c4ec5e9..2a5bdc75361d 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -37,6 +37,7 @@ android_library { "src/**/I*.aidl", ], resource_dirs: [ + "res-product", "res-keyguard", "res", ], @@ -91,6 +92,7 @@ android_library { manifest: "tests/AndroidManifest.xml", resource_dirs: [ "tests/res", + "res-product", "res-keyguard", "res", ], diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 6f6803817138..35147049e43e 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -325,6 +325,14 @@ android:permission="android.permission.BIND_WALLPAPER" android:exported="true" /> + <activity + android:name=".bubbles.BubbleOverflowActivity" + android:theme="@style/BubbleOverflow" + android:excludeFromRecents="true" + android:documentLaunchMode="always" + android:resizeableActivity="true"> + </activity> + <activity android:name=".tuner.TunerActivity" android:enabled="false" android:icon="@drawable/tuner" diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING index 26ec5726a4a2..9f13a7b861a0 100644 --- a/packages/SystemUI/TEST_MAPPING +++ b/packages/SystemUI/TEST_MAPPING @@ -9,12 +9,6 @@ "include-filter": "android.platform.test.scenario.sysui" }, { - "include-filter": "android.platform.test.scenario.quicksettings" - }, - { - "include-filter": "android.platform.test.scenario.notification" - }, - { "include-annotation": "android.platform.test.scenario.annotation.Scenario" }, { diff --git a/packages/SystemUI/docs/executors.md b/packages/SystemUI/docs/executors.md new file mode 100644 index 000000000000..8520ce228c9d --- /dev/null +++ b/packages/SystemUI/docs/executors.md @@ -0,0 +1,321 @@ +# Executors + +go/sysui-executors + +[TOC] + +## TLDR + +In SystemUI, we are encouraging the use of Java's [Executor][Executor] over +Android's [Handler][Handler] when shuffling a [Runnable][Runnable] between +threads or delaying the execution of a Runnable. We have an implementation of +Executor available, as well as our own sub-interface, +[DelayableExecutor][DelayableExecutor] available. For test, +[FakeExecutor][FakeExecutor] is available. + +[Executor]: https://developer.android.com/reference/java/util/concurrent/Executor.html +[Handler]: https://developer.android.com/reference/android/os/Handler +[Runnable]: https://developer.android.com/reference/java/lang/Runnable.html +[DelayableExecutor]: /packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java +[FakeExecutor]: /packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java + +## Rationale + +Executors make testing easier and are generally more flexible than Handlers. +They are defined as an interface, making it easy to swap in fake implementations +for testing. This also makes it easier to supply alternate implementations +generally speaking - shared thread pools; priority queues; etc. + +For testing, whereas a handler involves trying to directly control its +underlying Looper (using things like `Thread.sleep()` as well as overriding +internal behaviors), an Executor implementation can be made to be directly +controllable and inspectable. + +See also go/executors-for-the-android-engineer + +## Available Executors + +At present, there are two interfaces of Executor avaiable, each implemented, and +each with two instances - `@Background` and `@Main`. + +### Executor + +The simplest Executor available implements the interface directly, making +available one method: `Executor.execute()`. You can access an implementation of +this Executor through Dependency Injection: + +```java + public class Foobar { + @Inject + public Foobar(@Background Executor bgExecutor) { + bgExecutor.execute(new Runnable() { + // ... + }); + } + } +``` + +`@Main` will give you an Executor that runs on the ui thread. `@Background` will +give you one that runs on a _shared_ non-ui thread. If you ask for an +non-annotated Executor, you will get the `@Background` Executor. + +We do not currently have support for creating an Executor on a new, virgin +thread. We do not currently support any sort of shared pooling of threads. If +you require either of these, please reach out. + +### DelayableExecutor + +[DelayableExecutor][DelayableExecutor] is the closest analogue we provide to +Handler. It adds `executeDelayed(Runnable r, long delayMillis)` and +`executeAtTime(Runnable r, long uptimeMillis)` to the interface, just like +Handler's [postDelayed][postDelayed] and [postAtTime][postAttime]. It also adds +the option to supply a [TimeUnit][TimeUnit] as a third argument. + +A DelayableExecutor can be accessed via Injection just like a standard Executor. +In fact, at this time, it shares the same underlying thread as our basic +Executor. + +```java + public class Foobar { + @Inject + public Foobar(@Background DelayableExecutor bgExecutor) { + bgExecutor.executeDelayed(new Runnable() { + // ... + }, 1, TimeUnit.MINUTES); + } + } +``` + +Unlike Handler, the added methods return a Runnable that, when run, cancels the +originally supplied Runnable if it has not yet started execution: + +```java + public class Foobar { + @Inject + public Foobar(@Background DelayableExecutor bgExecutor) { + Runnable cancel = bgExecutor.executeDelayed(new Runnable() { + // ... + }, 1, TimeUnit.MINUTES); + + cancel.run(); // The supplied Runnable will (probably) not run. + } + } +``` + +[postDelayed]: https://developer.android.com/reference/android/os/Handler#postDelayed(java.lang.Runnable,%20long) +[postAttime]: https://developer.android.com/reference/android/os/Handler#postAtTime(java.lang.Runnable,%20long) +[TimeUnit]: https://developer.android.com/reference/java/util/concurrent/TimeUnit + +## Moving From Handler + +Most use cases of Handlers can easily be handled by the above two interfaces +above. A minor refactor makes the switch: + +Handler | Executor | DelayableExecutor +------------- | --------- | ----------------- +post() | execute() | execute() +postDelayed() | `none` | executeDelayed() +postAtTime() | `none` | executeAtTime() + +There is one notable gap in this implementation: `Handler.postAtFrontOfQueue()`. +If you require this method, or similar, please reach out. The idea of a +PriorityQueueExecutor has been floated, but will not be implemented until there +is a clear need. + +Note also that "canceling" semantics are different. Instead of passing a `token` +object to `Handler.postDelayed()`, you receive a Runnable that, when run, +cancels the originally supplied Runnable. + +### Message Handling + +Executors have no concept of message handling. This is an oft used feature of +Handlers. There are (as of 2019-12-05) 37 places where we subclass Handler to +take advantage of this. However, by-and-large, these subclases take the +following form: + +```Java +mHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_A: + handleMessageA(); + break; + case MSG_B: + handleMessageB((String) msg.obj); + break; + case MSG_C: + handleMessageC((Foobar) msg.obj); + break; + // ... + } + } +}; + +// Elsewhere in the class +void doSomething() { + mHandler.obtainMessage(MSG_B, "some string"); + mHandler.sendMessage(msg); +} +``` + +This could easily be replaced by equivalent, more direct Executor code: + +```Java +void doSomething() { + mExecutor.execute(() -> handleMessageB("some string")); +} +``` + +If you are posting Runnables frequently and you worry that the cost of creating +anonymous Runnables is too high, consider creating pre-defined Runnables as +fields in your class. + +If you feel that you have a use case that this does not cover, please reach out. + +### Handlers Are Still Necessary + +Handlers aren't going away. There are Android APIs that still require them (even +if future API development discourages them). A simple example is +[ContentObserver][ContentObserver]. Use them where necessary. + +[ContentObserver]: https://developer.android.com/reference/android/database/ContentObserver + +## Testing (FakeExecutor) + +We have a [FakeExecutor][FakeExecutor] available. It implements +DelayableExecutor (which in turn is an Executor). It takes a FakeSystemClock in +its constructor that allows you to control the flow of time, executing supplied +Runnables in a deterministic manner. + +The implementation is well documented and tested. You are encouraged to read and +reference it, but here is a quick overview: + +<table> + <tr> + <th>Method</th> + <th>Description</th> + </tr> + <tr> + <td>execute()</td> + <td> + Queues a Runnable so that it is "ready" + to run. (A Runnable is "ready" when its + scheduled time is less than or equal to + the clock.) + </td> + </tr> + <tr> + <td>postDelayed() & postAtTime()</td> + <td> + Queues a runnable to be run at some + point in the future. + </td> + </tr> + <tr> + <td>runNextReady()</td> + <td> + Run one runnable if it is ready to run + according to the supplied clock. + </td> + </tr> + <tr> + <td>runAllReady()</td> + <td> + Calls runNextReady() in a loop until + there are no more "ready" runnables. + </td> + </tr> + <tr> + <td>advanceClockToNext()</td> + <td> + Move the internal clock to the item at + the front of the queue, making it + "ready". + </td> + </tr> + <tr> + <td>advanceClockToLast()</td> + <td> + Makes all currently queued items ready. + </td> + </tr> + <tr> + <td>numPending()</td> + <td> + The number of runnables waiting to be run + They are not necessarily "ready". + </td> + </tr> + <tr> + <td>(static method) exhaustExecutors()</td> + <td> + Given a number of FakeExecutors, it + calls runAllReady() repeated on them + until none of them have ready work. + Useful if you have Executors that post + work to one another back and forth. + </td> + </tr> +</table> + +_If you advance the supplied FakeSystemClock directly, the FakeExecutor will +execute pending Runnables accordingly._ If you use the FakeExecutors +`advanceClockToNext()` and `advanceClockToLast()`, this behavior will not be +seen. You will need to tell the Executor to run its ready items. A quick example +shows the difference: + +Here we advance the clock directly: + +```java +FakeSystemClock clock = new FakeSystemClock(); +FakeExecutor executor = new FakeExecutor(clock); +executor.execute(() -> {}); // Nothing run yet. Runs at time-0 +executor.executeDelayed(() -> {}, 100); // Nothing run yet. Runs at time-100. +executor.executeDelayed(() -> {}, 500); // Nothing run yet. Runs at time-500. + +clock.synchronizeListeners(); // The clock just told the Executor it's time-0. + // One thing run. +clock.setUptimeMillis(500); // The clock just told the Executor it's time-500. + // Two more items run. +``` + +Here we have more fine-grained control: + +```java +FakeSystemClock clock = new FakeSystemClock(); +FakeExecutor executor = new FakeExecutor(clock); +executor.execute(() -> {}); // Nothing run yet. Runs at time-0 +executor.executeDelayed(() -> {}, 100); // Nothing run yet. Runs at time-100. +executor.executeDelayed(() -> {}, 500); // Nothing run yet. Runs at time-500. + +executor.runNextReady(); // One thing run. +executor.advanceClockToNext(); // One more thing ready to run. +executor.runNextReady(); // One thing run. +executor.runNextReady(); // Extra calls do nothing. (Returns false). +executor.advanceClockToNext(); // One more thing ready to run. +executor.runNextReady(); // Last item run. +``` + +One gotcha of direct-clock-advancement: If you have interleaved Runnables split +between two executors like the following: + +```java +FakeSystemClock clock = new FakeSystemClock(); +FakeExecutor executorA = new FakeExecutor(clock); +FakeExecutor executorB = new FakeExecutor(clock); +executorA.executeDelayed(() -> {}, 100); +executorB.executeDelayed(() -> {}, 200); +executorA.executeDelayed(() -> {}, 300); +executorB.executeDelayed(() -> {}, 400); +clock.setUptimeMillis(500); +``` + +The Runnables _will not_ interleave. All of one Executor's callbacks will run, +then all of the other's. + +### TestableLooper.RunWithLooper + +As long as you're using FakeExecutors in all the code under test (and no +Handlers or Loopers) you don't need it. Get rid of it. No more TestableLooper; +no more Looper at all, for that matter. diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java index b21a9f7c4d05..6c4cbdf27fa5 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java @@ -34,7 +34,8 @@ public interface StatusBarStateController { int getState(); /** - * Is device dozing + * Is device dozing. Dozing is when the screen is in AOD or asleep given that + * {@link com.android.systemui.doze.DozeService} is configured. */ boolean isDozing(); diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml index b285f118f439..b7f29a17b1ba 100644 --- a/packages/SystemUI/res-keyguard/values-af/strings.xml +++ b/packages/SystemUI/res-keyguard/values-af/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Druk Kieslys om te ontsluit."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netwerk is gesluit"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Geen SIM-kaart nie"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Geen SIM-kaart in tablet nie."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Geen SIM-kaart in foon nie."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Steek \'n SIM-kaart in."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Die SIM-kaart is weg of nie leesbaar nie. Steek \'n SIM-kaart in."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Onbruikbare SIM-kaart."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Tik \'n PIN wat 4 to 8 syfers lank is, in."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-kode moet 8 of meer syfers wees."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Voer die korrekte PUK-kode weer in. Herhaalde pogings sal die SIM permanent deaktiveer."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-kodes stem nie ooreen nie"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Te veel patroonpogings"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Jy het jou PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd ingetik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%2$d</xliff:g> sekondes."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Jy het jou wagwoord <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd ingetik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%2$d</xliff:g> sekondes."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%2$d</xliff:g> sekondes."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie tablet teruggestel word, wat al sy data sal uitvee."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie foon teruggestel word, wat al sy data sal uitvee."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie tablet sal teruggestel word, wat al sy data sal uitvee."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie foon sal teruggestel word, wat al sy data sal uitvee."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie gebruiker verwyder word, wat alle gebruikerdata sal uitvee."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie gebruiker verwyder word, wat alle gebruikerdata sal uitvee."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou tablet te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou foon te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Verkeerde SIM-PIN-kode. Jy sal nou jou diensverskaffer moet kontak om jou toestel te ontsluit."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Verkeerde SIM-PIN-kode. Jy het <xliff:g id="NUMBER_1">%d</xliff:g> pogings oor.</item> diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml index 855db55a5e4e..c94ba8bf22e8 100644 --- a/packages/SystemUI/res-keyguard/values-am/strings.xml +++ b/packages/SystemUI/res-keyguard/values-am/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ለመክፈት ምናሌ ተጫን።"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"አውታረ መረብ ተቆልፏል"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ምንም ሲም ካርድ የለም"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"በጡባዊ ውስጥ ምንም ሲም ካርድ የለም።"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"በስልክ ውስጥ ምንም ሲም ካርድ የለም።"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ሲም ካርድ ያስገቡ።"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ሲም ካርዱ ጠፍቷል ወይም መነበብ አይችልም። እባክዎ ሲም ካርድ ያስገቡ።"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"የማይሰራ ሲም ካርድ።"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"ከ4 እስከ 8 ቁጥሮች የያዘ ፒን ይተይቡ።"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"የPUK ኮድ 8 ወይም ከዚያ በላይ ቁጥሮች ሊኖረው ይገባል።"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"ትክክለኛውን የPUK ኮድ እንደገና ያስገቡ። ተደጋጋሚ ሙከራዎች ሲሙን እስከመጨረሻው ያሰናክሉታል።"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ፒን ኮዶቹ አይገጣጠሙም"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"በጣም ብዙ የስርዓተ ጥለት ሙከራዎች"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"ፒንዎን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልተየቡም። \n\nበ<xliff:g id="NUMBER_1">%2$d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"የይለፍ ቃልዎን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መንገድ ተይበዋል።\n\nበ<xliff:g id="NUMBER_1">%2$d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መንገድ ስለውታል።\n\nበ<xliff:g id="NUMBER_1">%2$d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ጡባዊውን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ጡባዊ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂብ ይሰርዛል።"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ስልኩን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ስልክ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂብ ይሰርዛል።"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ጡባዊውን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ ሁኔታ ለማስከፈት ሞክረዋል። ስልኩ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ ሁኔታ ለማስከፈት ሞክረዋል። ስልኩ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ጡባዊውን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ስልኩን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ጡባዊውን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለመክፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለመክፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ጡባዊዎን እንዲከፍቱ ይጠየቃሉ።\n\n ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ከሰከንዶች በኋላ እንደገና ይሞክሩ።"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ልክ ያልሆነ የሲም ፒን ኮድ። አሁን መሣሪያዎን ለማስከፈት አገልግሎት አቅራቢዎን ማነጋገር አለብዎት።"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">ልክ ያልሆነ የሲም ፒን ኮድ፣ <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል።</item> diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml index 668957a26eb4..fe10afa48b4f 100644 --- a/packages/SystemUI/res-keyguard/values-ar/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"اضغط على \"القائمة\" لإلغاء التأمين."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"الشبكة مؤمّنة"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ليست هناك شريحة SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ليست هناك شريحة SIM في الجهاز اللوحي."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ليست هناك شريحة SIM في الهاتف."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"أدخل شريحة SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"شريحة SIM مفقودة أو غير قابلة للقراءة. أدخل شريحة SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"شريحة SIM غير قابلة للاستخدام."</string> @@ -87,17 +85,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"اكتب رمز رقم التعريف الشخصي المكوّن من ٤ إلى ٨ أرقام."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"يجب أن يتضمن رمز PUK ۸ أرقام أو أكثر."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"أعد إدخال رمز PUK الصحيح. وستؤدي المحاولات المتكررة إلى إيقاف شريحة SIM نهائيًا."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"لا يتطابق رمز رقم التعريف الشخصي"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"محاولات النقش كثيرة جدًا"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"لقد كتبت رقم التعريف الشخصي بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانية."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"لقد كتبت كلمة المرور بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانية."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"لقد رسمت نقش فتح القفل بطريقة غير صحيحة <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانية."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إعادة تعيين هذا الجهاز، ومن ثم يتم حذف جميع بياناته."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إعادة تعيين هذا الهاتف، ومن ثم يتم حذف جميع بياناته."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إعادة تعيين هذا الجهاز، ومن ثم يتم حذف جميع بياناته."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إعادة تعيين هذا الهاتف، ومن ثم يتم حذف جميع بياناته."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إزالة هذا المستخدم، ومن ثم يتم حذف جميع بيانات المستخدم."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إزالة هذا المستخدم، ومن ثم يتم حذف جميع بيانات المستخدم."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -106,10 +97,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"رمز \"رقم التعريف الشخصي\" لشريحة SIM غير صحيح، ويلزمك الاتصال الآن بمشغّل شبكة الجوّال لإلغاء قفل الجهاز."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="zero">رمز رقم التعريف الشخصي لشريحة SIM غير صحيح، ولم تتبق لديك أي محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>).</item> diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml index 3fef9d7b532e..f814c3a0e979 100644 --- a/packages/SystemUI/res-keyguard/values-as/strings.xml +++ b/packages/SystemUI/res-keyguard/values-as/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"আনলক কৰিবলৈ মেনু টিপক।"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"নেটৱর্ক লক কৰা অৱস্থাত আছে"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"কোনো ছিম কাৰ্ড নাই"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"টেবলেটত ছিম কার্ড নাই।"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ফ\'নত ছিম কার্ড নাই।"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"এখন ছিম কাৰ্ড ভৰাওক।"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ছিম কাৰ্ডখন নাই বা চিনাক্ত কৰিব নোৱাৰি। এখন ছিম কাৰ্ড ভৰাওক।"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ব্যৱহাৰৰ অযোগ্য ছিম কাৰ্ড।"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"৪টাৰ পৰা ৮টা সংখ্যাযুক্ত এটা পিন লিখক।"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK ক\'ডটো ৮টা বা তাতকৈ অধিক সংখ্যা থকা হ\'ব লাগিব।"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"শুদ্ধ PUK ক\'ডটো পুনৰ দিয়ক। বাৰে বাৰে ভুল ক\'ড দিলে ছিমখন স্থায়ীভাৱে অক্ষম হ\'ব।"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"পিন ক\'ড মিলা নাই"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"বহুতবাৰ ভুলকৈ আর্হি অঁকা হৈছে"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"আপুনি আপোনাৰ পিন <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ লিখিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"আপুনি আপোনাৰ পাছৱৰ্ড <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ লিখিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ছেকেণ্ডৰ পাছত আকৌ চেষ্টা কৰক।"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"আপুনি আপোনাৰ আনলক আৰ্হি <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে টেবলেটটো ৰিছেট কৰা হ\'ব, যি কার্যই টেবলেটটোত থকা সকলো ডেটা মচিব।"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে ফ\'নটো ৰিছেট কৰা হ\'ব, যি কার্যই ফ\'নটোত থকা সকলো ডেটা মচিব।"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। এই টেবলেটটো ৰিছেট কৰা হ\'ব, যি কার্যই ইয়াৰ সকলো ডেটা মচিব।"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। এই ফ\'নটো ৰিছেট কৰা হ\'ব, যিয়ে ইয়াৰ সকলো ডেটা মচিব।"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে এই ব্যৱহাৰকাৰীক আঁতৰোৱা হ\'ব, যিয়ে ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব।"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে এই ব্যৱহাৰকাৰীক আঁতৰোৱা হ\'ব, যিয়ে ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব।"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলটো আঁতৰোৱা হ\'ব, যি কার্যই প্ৰ\'ফাইলটোৰ সকলো ডেটা মচিব।"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলটো আঁতৰোৱা হ\'ব, যিয়ে প্ৰ\'ফাইলটোৰ সকলো ডেটা মচিব।"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"আপুনি আপোনাৰ আনলক আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল আৰ্হি আঁকিলে আপোনাৰ টেবলেটটো কোনো একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ\'ব।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"আপুনি আপোনাৰ আনলক আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল আৰ্হি আঁকিলে আপোনাৰ ফ\'নটো কোনো একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ\'ব।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ছিমৰ ভুল পিন ক\'ড, আপোনাৰ ডিভাইচটো আনলক কৰিবলৈ আপুনি এতিয়া আপোনাৰ বাহকৰ সৈতে যোগাযোগ কৰিবই লাগিব।"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">ছিমৰ ভুল পিন ক’ড, আপুনি আৰু <xliff:g id="NUMBER_1">%d</xliff:g> বাৰ প্ৰয়াস কৰিব পাৰিব।</item> diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml index 8bc953e82a9a..e04f3054d0dd 100644 --- a/packages/SystemUI/res-keyguard/values-az/strings.xml +++ b/packages/SystemUI/res-keyguard/values-az/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Kilidi açmaq üçün Menyu düyməsinə basın."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Şəbəkə kilidlidir"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM kart yoxdur."</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planşetdə SIM kart yoxdur."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonda SIM kart yoxdur."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM kart daxil edin."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM kart yoxdur və ya oxuna bilinmir. SIM kart daxil edin."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Yararsız SIM kart."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4-8 rəqəmli PIN daxil edin."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kod 8 rəqəm və ya daha çox olmalıdır."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Yenidən düzgün PUK kod daxil edin. Təkrarlanan cəhdlər SIM-i birdəfəlik sıradan çıxaracaq."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodlar uyğun gəlmir"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Həddindən çox model cəhdi"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN kodu <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış daxil etdiniz. \n \n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniyə sonra yenidən cəhd edin."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Parolu <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış daxil etdiniz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniyə sonra yenidən cəhd edin."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Kilid modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkdiniz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniyə sonra yenidən cəhd edin."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu planşet sıfırlanacaq və bütün data silinəcək."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu telefon sıfırlanacaq və bütün data silinəcək."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Bu planşet sıfırlanacaq və bütün data silinəcək."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Bu telefon sıfırlanacaq və bütün data silinəcək."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu istifadəçi silinəcək və bütün istifadəçi datası ləğv ediləcək."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu istifadəçi silinəcək və bütün istifadəçi datası ləğv ediləcək."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Yanlış SIM PIN kodu cihazın açılması üçün operatorla indi əlaqə saxlamalısınız."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Yanlış SIM PIN kodu, <xliff:g id="NUMBER_1">%d</xliff:g> cəhdiniz qalır.</item> 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 116e096012ad..82dca6b95afe 100644 --- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pritisnite Meni da biste otključali."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nema SIM kartice"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"U tabletu nema SIM kartice."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"U telefonu nema SIM kartice."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Umetnite SIM karticu."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM kartica nedostaje ili ne može da se pročita. Umetnite SIM karticu."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM kartica je neupotrebljiva."</string> @@ -84,17 +82,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Unesite PIN koji ima 4–8 brojeva."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kôd treba da ima 8 ili više brojeva."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Ponovo unesite tačan PUK kôd. Ponovljeni pokušaji će trajno onemogućiti SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodovi se ne podudaraju"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Previše pokušaja unosa šablona"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Uneli ste pogrešan PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Uneli ste pogrešnu lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Nacrtali ste netačan šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, ovaj tablet će se resetovati, čime se brišu svi podaci korisnika."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, ovaj telefon će se resetovati, čime se brišu svi podaci korisnika."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Ovaj tablet će se resetovati, čime se brišu svi podaci."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Ovaj telefon će se resetovati, čime se brišu svi podaci."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo ovog korisnika, čime se brišu svi podaci korisnika."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo ovog korisnika, čime se brišu svi podaci korisnika."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -103,10 +94,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo profil za Work, čime se brišu svi podaci sa profila."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo profil za Work, čime se brišu svi podaci sa profila."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate tablet pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate telefon pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Netačan PIN kôd za SIM. Sada morate da kontaktirate mobilnog operatera da biste otključali uređaj."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Netačan PIN kôd za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item> diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml index 5bb89aeb5cc7..d9a450846f0b 100644 --- a/packages/SystemUI/res-keyguard/values-be/strings.xml +++ b/packages/SystemUI/res-keyguard/values-be/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Націсніце кнопку \"Меню\", каб разблакіраваць."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сетка заблакіравана"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Няма SIM-карты"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"У планшэце няма SIM-карты."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"У тэлефоне няма SIM-карты."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Устаўце SIM-карту."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-карта адсутнічае ці не чытаецца. Устаўце SIM-карту."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM-карту немагчыма выкарыстоўваць."</string> @@ -85,17 +83,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Увядзіце PIN-код, які змяшчае ад 4 да 8 лічбаў."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-код павінен утрымліваць 8 лічбаў ці больш."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Паўторна ўвядзіце правільны PUK-код. Паўторныя спробы прывядуць да адключэння SIM-карты назаўсёды."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коды не супадаюць"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Занадта шмат спроб уводу ўзору"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Вы няправільна ўвялі PIN-код столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Вы няправільна ўвялі пароль столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Цяпер ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Цяпер ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) гэты карыстальнік будзе выдалены, гэта прывядзе да выдалення ўсіх карыстальніцкіх даных."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) гэты карыстальнік будзе выдалены, гэта прывядзе да выдалення ўсіх карыстальніцкіх даных."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -104,10 +95,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, гэта прывядзе да выдалення ўсіх даных у профілі."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, гэта прывядзе да выдалення ўсіх даных у профілі."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць планшэт, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць тэлефон, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Няправільны PIN-код SIM-карты, цяпер вы павінны звязацца з аператарам для разблакіроўкі прылады."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Няправільны PIN-код SIM-карты, у вас засталася <xliff:g id="NUMBER_1">%d</xliff:g> спроба.</item> diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml index 2b37c5269251..3b68a42a5ce7 100644 --- a/packages/SystemUI/res-keyguard/values-bg/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Натиснете „Меню“, за да отключите."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежата е заключена"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Няма SIM карта"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"В таблета няма SIM карта."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"В телефона няма SIM карта."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Поставете SIM карта."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM картата липсва или е нечетлива. Поставете SIM карта."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Неизползваема SIM карта."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Въведете ПИН код с четири до осем цифри."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK кодът трябва да е с осем или повече цифри."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Въведете отново правилния PUK код. Многократните опити ще деактивират за постоянно SIM картата."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ПИН кодовете не съвпадат"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Опитите за фигурата са твърде много"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Въведохте неправилно ПИН кода си <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%2$d</xliff:g> секунди."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Въведохте неправилно паролата си <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%2$d</xliff:g> секунди."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%2$d</xliff:g> секунди."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита той ще бъде нулиран, при което ще се изтрият всичките му данни."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита той ще бъде нулиран, при което ще се изтрият всичките му данни."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Той ще бъде нулиран, при което ще се изтрият всичките му данни."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Той ще бъде нулиран, при което ще се изтрият всичките му данни."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета си посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Неправилен ПИН код за SIM картата – сега трябва да се свържете с оператора си, за да отключите устройството."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Неправилен ПИН код за SIM картата – остават ви <xliff:g id="NUMBER_1">%d</xliff:g> опита.</item> diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml index 26881d8ac273..7d0d4b926277 100644 --- a/packages/SystemUI/res-keyguard/values-bn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"আনলক করতে মেনুতে টিপুন।"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"নেটওয়ার্ক লক করা আছে"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"কোনো সিম কার্ড নেই"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ট্যাবলেটের মধ্যে কোনো সিম কার্ড নেই।"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ফোনের মধ্যে কোনো সিম কার্ড নেই।"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"একটি সিম কার্ড লাগান।"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"সিম কার্ড নেই বা সেটি পড়া যাচ্ছে না। একটি সিম কার্ড লাগান।"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"অব্যবহারযোগ্য সিম কার্ড।"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"একটি ৪ থেকে ৮ সংখ্যার পিন লিখুন।"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK কোডটি ৮ বা তার বেশি সংখ্যার হতে হবে।"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"সঠিক PUK কোডটি পুনরায় লিখুন। বার বার চেষ্টা করা হলে সিমটি স্থায়ীভাবে অক্ষম হয়ে যাবে।"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"পিন কোডগুলি মিলছে না"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"বিভিন্ন প্যাটার্নের সাহায্যে খুব বেশি বার প্রচেষ্টা করা হয়ে গেছে"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"আপনি আপনার পিন টাইপ করতে <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল করেছেন৷ \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে আপনার পাসওয়ার্ড লিখেছেন।\n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে আপনার আনলকের প্যাটার্ন এঁকেছেন।\n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ট্যাবলেটটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ফোনটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। এই ফোনটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। এই ফোনটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ব্যবহারকারীকে সরিয়ে দেওয়া হবে, যার ফলে ব্যবহারকারীর সমস্ত ডেটা মুছে যাবে।"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ব্যবহারকারীকে সরিয়ে দেওয়া হবে, যার ফলে ব্যবহারকারীর সমস্ত ডেটা মুছে যাবে।"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। কাজের প্রোফাইলটি সরিয়ে দেওয়া হবে, যার ফলে প্রোফাইলের সমস্ত ডেটা মুছে যাবে।"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। কাজের প্রোফাইলটি সরিয়ে দেওয়া হবে, যার ফলে প্রোফাইলের সমস্ত ডেটা মুছে যাবে।"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে আনলকের প্যাটার্ন এঁকেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর আপনাকে একটি ইমেল অ্যাকাউন্টের মাধ্যমে আপনার ট্যাবলেটটি আনলক করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে আনলকের প্যাটার্ন এঁকেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর আপনাকে একটি ইমেল অ্যাকাউন্টের মাধ্যমে আপনার ফোনটি আনলক করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ভুল সিম পিন কোড দিয়েছেন, আপনার ডিভাইসটি আনলক করতে এখন আপনাকে অবশ্যই আপনার পরিষেবা প্রদানকারীর সাথে যোগাযোগ করতে হবে।"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">সিমের পিন কোডটি ভুল, আপনি আর <xliff:g id="NUMBER_1">%d</xliff:g> বার চেষ্টা করতে পারেন।</item> diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml index 9e36a725fdb3..99140ce543ea 100644 --- a/packages/SystemUI/res-keyguard/values-bs/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pritisnite meni da otključate."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nema SIM kartice"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nema SIM kartice u tabletu."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nema SIM kartice u telefonu."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Umetnite SIM karticu."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM kartica nije umetnuta ili je uređaj ne može očitati. Umetnite SIM karticu."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Neupotrebljiva SIM kartica."</string> @@ -84,17 +82,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Unesite PIN koji sadrži 4 do 8 brojeva."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kôd treba sadržavati najmanje 8 brojeva."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Ponovo unesite ispravan PUK kôd. Ponovljeni pokušaji će trajno onemogućiti SIM karticu."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-ovi se ne poklapaju"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Previše puta ste pokušali otključati uređaj crtanjem uzorka"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Pogrešno ste unijeli PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Pogrešno ste unijeli lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Pogrešno ste nacrtali svoj uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati tablet. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, tablet će se vratiti na fabričke postavke i svi podaci će se izbrisati."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, telefon će se vratiti na fabričke postavke i svi podaci će se izbrisati."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Tablet će se sada vratiti na fabričke postavke i svi podaci će se izbrisati."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati telefon. Telefon će se sada vratiti na fabričke postavke i svi podaci će se izbrisati."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati tablet. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, ovaj korisnik će se ukloniti i svi podaci korisnika će se izbrisati."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, ovaj korisnik će se ukloniti i svi podaci korisnika će se izbrisati."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -103,10 +94,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Poslovni profil će se ukloniti i svi podaci s profila će se izbrisati."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati telefon. Poslovni profil će se ukloniti i svi podaci s profila će se izbrisati."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da tablet otključate koristeći račun e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da telefon otključate koristeći račun e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"PIN za SIM karticu je netačan. Za otključavanje uređaja sada se morate obratiti svom operateru."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">PIN za SIM karticu je netačan. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item> diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml index 8059ec349cad..7bb3677e3316 100644 --- a/packages/SystemUI/res-keyguard/values-ca/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Prem Menú per desbloquejar."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"La xarxa està bloquejada"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"No hi ha cap SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No hi ha cap SIM a la tauleta."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No hi ha cap SIM al telèfon."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insereix una targeta SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Falta la targeta SIM o no es pot llegir. Insereix-ne una."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"La targeta SIM no es pot fer servir."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Escriu un PIN que tingui entre 4 i 8 números."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"El codi PUK ha de tenir 8 números o més."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Torna a introduir el codi PUK correcte. Si ho intentes diverses vegades, es desactivarà la SIM permanentment."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Els codis PIN no coincideixen"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Has intentat dibuixar el patró massa vegades"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Has escrit el PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%2$d</xliff:g> segons."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Has escrit la contrasenya <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%2$d</xliff:g> segons."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%2$d</xliff:g> segons."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, la tauleta es restablirà i se\'n suprimiran totes les dades."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, el telèfon es restablirà i se\'n suprimiran totes les dades."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. La tauleta es restablirà i se\'n suprimiran totes les dades."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El telèfon es restablirà i se\'n suprimiran totes les dades."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, l\'usuari se suprimirà, juntament amb totes les seves dades."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, l\'usuari se suprimirà, juntament amb totes les seves dades."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"El codi PIN de la SIM no és correcte. Contacta amb l\'operador de telefonia mòbil per desbloquejar el dispositiu."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">El codi PIN de la SIM no és correcte. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents.</item> diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml index b8bfe07bbaec..7e430d6d9d3d 100644 --- a/packages/SystemUI/res-keyguard/values-cs/strings.xml +++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Klávesy odemknete stisknutím tlačítka nabídky."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Síť je blokována"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Chybí SIM karta"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"V tabletu není SIM karta."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"V telefonu není SIM karta."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Vložte SIM kartu."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM karta chybí nebo je nečitelná. Vložte SIM kartu."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Nepoužitelná SIM karta."</string> @@ -85,17 +83,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Zadejte kód PIN o délce 4–8 číslic."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Minimální délka kódu PUK je 8 číslic."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Znovu zadejte správný kód PUK. Opakovanými pokusy SIM kartu trvale zablokujete."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kódy PIN se neshodují"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Příliš mnoho pokusů o zadání gesta"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste zadali nesprávný kód PIN. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali heslo. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste zadali nesprávné bezpečnostní gesto. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tablet resetován, čímž se z něj smažou všechna data."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude telefon resetován, čímž se z něj smažou všechna data."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Tablet bude resetován, čímž z něj budou smazána všechna data."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Telefon bude resetován, čímž z něj budou smazána všechna data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tento uživatel odstraněn, čímž se smažou všechna jeho data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tento uživatel odstraněn, čímž se smažou všechna jeho data."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -104,10 +95,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Zadali jste nesprávný kód PIN SIM karty. Nyní musíte za účelem odemknutí zařízení kontaktovat svého operátora."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="few">Zadali jste nesprávný kód PIN SIM karty. Máte ještě <xliff:g id="NUMBER_1">%d</xliff:g> pokusy.</item> diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml index f134734706d9..a66f02b92465 100644 --- a/packages/SystemUI/res-keyguard/values-da/strings.xml +++ b/packages/SystemUI/res-keyguard/values-da/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Tryk på menuen for at låse op."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netværket er låst"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Intet SIM-kort"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Der er ikke noget SIM-kort i denne tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Der er ikke noget SIM-kort i telefonen."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Indsæt et SIM-kort."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-kortet mangler eller kan ikke læses. Indsæt et SIM-kort."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Ubrugeligt SIM-kort."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Angiv en pinkode på mellem 4 og 8 tal."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-koden skal være på 8 tal eller mere."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Angiv den korrekte PUK-kode. Gentagne forsøg deaktiverer permanent SIM-kortet."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Pinkoderne stemmer ikke overens"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Du har brugt for mange forsøg på at tegne mønsteret korrekt"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du har forsøgt at låse denne tablet op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg nulstilles denne tablet, hvilket sletter alle dens data."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du har forsøgt at låse telefonen op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg nulstilles denne telefon, hvilket sletter alle dens data."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du har forsøgt at låse denne tablet op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Denne tablet nulstilles, hvilket sletter alle dens data."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du har forsøgt at låse telefonen op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Telefonen nulstilles, hvilket sletter alle dens data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du har forsøgt at låse denne tablet op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket sletter alle brugerdata."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du har forsøgt at låse telefonen op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket sletter alle brugerdata."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du har forsøgt at låse denne tablet op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket sletter alle profildata."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du har forsøgt at låse telefonen op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket sletter alle profildata."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din tablet op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din telefon op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Forkert pinkode til SIM-kort. Du er nu nødt til at kontakte dit mobilselskab for at låse din enhed op."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Forkert pinkode til SIM-kort. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage.</item> diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml index abc43da6469b..7c0839acf496 100644 --- a/packages/SystemUI/res-keyguard/values-de/strings.xml +++ b/packages/SystemUI/res-keyguard/values-de/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Zum Entsperren die Menütaste drücken."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netzwerk gesperrt"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Keine SIM-Karte"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Keine SIM-Karte im Tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Keine SIM-Karte im Telefon."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM-Karte einlegen."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-Karte fehlt oder ist nicht lesbar. Bitte lege eine SIM-Karte ein."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM-Karte unbrauchbar."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Gib eine 4- bis 8-stellige PIN ein."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Der PUK-Code muss mindestens 8 Ziffern aufweisen."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Gib den richtigen PUK-Code ein. Bei wiederholten Versuchen wird die SIM-Karte dauerhaft deaktiviert."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-Codes stimmen nicht überein"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Zu viele Musterversuche"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Du hast deine PIN <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nBitte versuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Du hast dein Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nBitte versuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. \n\nBitte versuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieses Tablet zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieses Telefon zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Dieses Tablet wird nun zurückgesetzt und alle Gerätedaten werden gelöscht."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Dieses Telefon wird nun zurückgesetzt und alle Gerätedaten werden gelöscht."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieser Nutzer entfernt. Dadurch werden alle Nutzerdaten gelöscht."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieser Nutzer entfernt. Dadurch werden alle Nutzerdaten gelöscht."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Falscher PIN-Code der SIM-Karte. Bitte wende dich an deinen Mobilfunkanbieter, damit er dein Gerät entsperrt."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Falscher PIN-Code der SIM-Karte. Du hast noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche.</item> diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml index 042a831b32e1..e9bd207a6f12 100644 --- a/packages/SystemUI/res-keyguard/values-el/strings.xml +++ b/packages/SystemUI/res-keyguard/values-el/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Πατήστε \"Μενού\" για ξεκλείδωμα."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Κλειδωμένο δίκτυο"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Δεν υπάρχει κάρτα SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Δεν υπάρχει κάρτα SIM στο tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Δεν υπάρχει κάρτα SIM στο τηλέφωνο."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Τοποθετήστε μια κάρτα SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Η κάρτα SIM δεν υπάρχει ή δεν είναι δυνατή η ανάγνωσή της. Τοποθετήστε μια κάρτα SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Η κάρτα SIM δεν μπορεί να χρησιμοποιηθεί."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Πληκτρολογήστε έναν αριθμό PIN που να αποτελείται από 4 έως 8 αριθμούς."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Ο κωδικός PUK θα πρέπει να περιέχει τουλάχιστον 8 αριθμούς."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Εισαγάγετε ξανά τον κωδικό PUK. Οι επαναλαμβανόμενες προσπάθειες θα απενεργοποιήσουν οριστικά την κάρτα SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Δεν υπάρχει αντιστοιχία μεταξύ των κωδικών PIN"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Πάρα πολλές προσπάθειες μοτίβου!"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Έχετε πληκτρολογήσει τον αριθμό PIN εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. \n\nΠροσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%2$d</xliff:g> δευτερόλεπτα."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Έχετε πληκτρολογήσει τον κωδικό πρόσβασης εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. \n\nΠροσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%2$d</xliff:g> δευτερόλεπτα."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος<xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. \n\nΠροσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%2$d</xliff:g> δευτερόλεπτα."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτό το tablet θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτό το τηλέφωνο θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Δοκιμάσατε να ξεκλειδώσετε αυτό το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτό το tablet θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτό το τηλέφωνο θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτός ο χρήστης θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα χρήστη."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτός ο χρήστης θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα χρήστη."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα προφίλ."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα προφίλ."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το tablet με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Λανθασμένος κωδικός PIN κάρτας SIM. Θα πρέπει να επικοινωνήσετε με την εταιρεία κινητής τηλεφωνίας σας για να ξεκλειδώσετε τη συσκευή σας."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Λανθασμένος κωδικός PIN κάρτας SIM. Απομένουν άλλες <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες.</item> diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml index 6d95c6ad02b9..969a8d67921d 100644 --- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"No SIM card"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insert a SIM card."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"The SIM card is missing or not readable. Insert a SIM card."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Unusable SIM card."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Type a PIN that is 4 to 8 numbers."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK code should be 8 numbers or more."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Too many pattern attempts"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Incorrect SIM PIN code. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item> diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml index d594cd0a2e1a..fcc08878668b 100644 --- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"No SIM card"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insert a SIM card."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"The SIM card is missing or not readable. Insert a SIM card."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Unusable SIM card."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Type a PIN that is 4 to 8 numbers."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK code should be 8 numbers or more."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Too many pattern attempts"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Incorrect SIM PIN code. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item> diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml index 6d95c6ad02b9..969a8d67921d 100644 --- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"No SIM card"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insert a SIM card."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"The SIM card is missing or not readable. Insert a SIM card."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Unusable SIM card."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Type a PIN that is 4 to 8 numbers."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK code should be 8 numbers or more."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Too many pattern attempts"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Incorrect SIM PIN code. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item> diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml index 6d95c6ad02b9..969a8d67921d 100644 --- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"No SIM card"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insert a SIM card."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"The SIM card is missing or not readable. Insert a SIM card."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Unusable SIM card."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Type a PIN that is 4 to 8 numbers."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK code should be 8 numbers or more."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Too many pattern attempts"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Incorrect SIM PIN code. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item> diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml index b8a6f108dbfc..975b1f644ef8 100644 --- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"No SIM card"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insert a SIM card."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"The SIM card is missing or not readable. Insert a SIM card."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Unusable SIM card."</string> @@ -83,25 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Type a PIN that is 4 to 8 numbers."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK code should be 8 numbers or more."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes does not match"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Too many pattern attempts"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> - <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="9046628517316763961">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This user will be removed, which will delete all user data."</string> - <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="3588779327358321092">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This user will be removed, which will delete all user data."</string> - <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="6114158710353725041">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string> - <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="8345451368768804892">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Incorrect SIM PIN code you must now contact your carrier to unlock your device."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item> diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml index 411f855484c4..80df3be320b9 100644 --- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml +++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Presiona Menú para desbloquear."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada para la red"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Sin tarjeta SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No hay tarjeta SIM en la tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No hay tarjeta SIM en el teléfono."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Inserta una tarjeta SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Falta la tarjeta SIM o no se puede leer. Introduce una tarjeta SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Tarjeta SIM inutilizable"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Escribe un PIN que tenga entre 4 y 8 números."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"El código PUK debe tener al menos 8 números."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Vuelve a ingresar el código PUK correcto. Si ingresas un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Los códigos PIN no coinciden"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Demasiados intentos incorrectos para el ingreso del patrón"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Escribiste tu PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Escribiste tu contraseña <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Dibujaste tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá la tablet, lo que borrará todos los datos."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá el teléfono, lo que borrará todos los datos."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se restablecerá la tablet, lo que borrará todos los datos."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se restablecerá el teléfono, lo que borrará todos los datos."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se quitará este usuario, lo que borrará todos los datos asociados."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se quitará este usuario, lo que borrará todos los datos asociados."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se quitará el perfil de trabajo, lo que borrará todos los datos asociados."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se quitará el perfil de trabajo, lo que borrará todos los datos asociados."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tablet mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"El código PIN de la tarjeta SIM es incorrecto. Debes comunicarte con tu proveedor para desbloquear el dispositivo."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">El código PIN de la tarjeta SIM es incorrecto. Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos más.</item> diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml index 4430046665e6..abfaf3a451c8 100644 --- a/packages/SystemUI/res-keyguard/values-es/strings.xml +++ b/packages/SystemUI/res-keyguard/values-es/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pulsa el menú para desbloquear la pantalla."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada para la red"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Falta la tarjeta SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No se ha insertado ninguna tarjeta SIM en el tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No se ha insertado ninguna tarjeta SIM en el teléfono."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Inserta una tarjeta SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Falta la tarjeta SIM o no se puede leer. Inserta una tarjeta SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"La tarjeta SIM se ha inhabilitado."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Escribe un código PIN que tenga entre 4 y 8 dígitos."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"El código PUK debe tener 8 números como mínimo."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Vuelve a introducir el código PUK correcto. Si introduces un código incorrecto varias veces, se inhabilitará la tarjeta SIM de forma permanente."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Los códigos PIN no coinciden"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Has fallado demasiadas veces al introducir el patrón"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al escribir el PIN. \n\nVuelve a intentarlo dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al introducir la contraseña. \n\nVuelve a intentarlo dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. \n\nVuelve a intentarlo dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el tablet. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se recuperarán los ajustes de fábrica de este tablet y se eliminarán todos sus datos."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el teléfono. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se recuperarán los ajustes de fábrica de este teléfono y se eliminarán todos sus datos."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el tablet. Se recuperarán los ajustes de fábrica de este tablet y se eliminarán todos sus datos."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el teléfono. Se recuperarán los ajustes de fábrica de este teléfono y se eliminarán todos sus datos."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el tablet. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se quitará a este usuario y se eliminarán todos sus datos."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el teléfono. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se quitará a este usuario y se eliminarán todos sus datos."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el tablet. Se quitará este perfil de trabajo se quitará y se eliminarán todos sus datos."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el teléfono. Se quitará este perfil de trabajo y se eliminarán todos sus datos."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, tendrás que usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, tendrás que usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"El código PIN de la tarjeta SIM es incorrecto. Debes ponerte en contacto con tu operador para desbloquear el dispositivo."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">El código PIN de la tarjeta SIM es incorrecto. Quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item> diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml index 888a57f9e200..bf8d06718a9e 100644 --- a/packages/SystemUI/res-keyguard/values-et/strings.xml +++ b/packages/SystemUI/res-keyguard/values-et/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Vajutage avamiseks menüüklahvi."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Võrk on lukus"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM-kaarti pole"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tahvelarvutis pole SIM-kaarti."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonis pole SIM-kaarti."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Sisestage SIM-kaart."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-kaart puudub või on loetamatu. Sisestage SIM-kaart."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Kasutamiskõlbmatu SIM-kaart."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Sisestage 4–8-numbriline PIN-kood."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-koodi pikkus peab olema vähemalt kaheksa numbrit."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Sisestage uuesti õige PUK-kood. Korduvkatsete korral keelatakse SIM-kaart jäädavalt."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-koodid ei ole vastavuses"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Liiga palju mustrikatseid"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Olete PIN-koodi <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti sisestanud. \n\nProovige <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundi pärast uuesti."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Olete parooli <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti sisestanud. \n\nProovige <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundi pärast uuesti."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Olete oma avamismustrit <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti joonistanud. \n\nProovige <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundi pärast uuesti."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset tahvelarvuti lähtestatakse ja kõik selle andmed kustutatakse."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset telefon lähtestatakse ja kõik selle andmed kustutatakse."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda tahvelarvutit valesti avada. Tahvelarvuti lähtestatakse ja kõik selle andmed kustutatakse."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda telefoni valesti avada. Telefon lähtestatakse ja kõik selle andmed kustutatakse."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutajaandmed kustutatakse."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutajaandmed kustutatakse."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda tahvelarvutit valesti avada. Tööprofiil eemaldatakse ja kõik profiiliandmed kustutatakse."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda telefoni valesti avada. Tööprofiil eemaldatakse ja kõik profiiliandmed kustutatakse."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM-kaardi vale PIN-kood. Seadme avamiseks peate nüüd ühendust võtma oma operaatoriga."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM-kaardi vale PIN-kood. Teil on jäänud veel <xliff:g id="NUMBER_1">%d</xliff:g> katset.</item> diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml index 117305f0d30f..6cf00d8f458f 100644 --- a/packages/SystemUI/res-keyguard/values-eu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Desblokeatzeko, sakatu Menua."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sarea blokeatuta dago"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Ez dago SIM txartelik"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Ez dago SIM txartelik tabletan."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Ez dago SIM txartelik telefonoan."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Sartu SIM txartela."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM txartela falta da edo ezin da irakurri. Sartu SIM txartel bat."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM txartela erabilgaitza da."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Idatzi 4 eta 8 zenbaki bitarteko PIN bat."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kodeak 8 zenbaki izan behar ditu gutxienez."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Idatzi berriro PUK kode zuzena. Hainbat saiakera oker eginez gero, betiko desgaituko da SIM txartela."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodeak ez datoz bat"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Eredua marrazteko saiakera gehiegi egin dira"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz idatzi duzu PIN kodea, baina huts egin duzu denetan. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz idatzi duzu pasahitza, baina huts egin duzu denetan. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz marraztu duzu desblokeatzeko eredua, baina huts egin duzu denetan. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, berrezarri egingo da tableta eta, ondorioz, bertako datu guztiak ezabatuko dira."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, berrezarri egingo da telefonoa eta, ondorioz, bertako datu guztiak ezabatuko dira."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Tableta berrezarri egingo da eta, ondorioz, bertako datu guztiak ezabatuko dira."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Telefonoa berrezarri egingo da eta, ondorioz, bertako datu guztiak ezabatuko dira."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, kendu egingo da erabiltzailea eta, ondorioz, haren datu guztiak ezabatuko dira."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, kendu egingo da erabiltzailea eta, ondorioz, haren datu guztiak ezabatuko dira."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz marraztu duzu desblokeatzeko eredua, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, tableta posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz marraztu duzu desblokeatzeko eredua, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM txartelaren PIN kodea ez da zuzena. Gailua desblokeatzeko, operadorearekin jarri beharko duzu harremanetan."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Ez da zuzena SIM txartelaren PIN kodea. <xliff:g id="NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu gailua desblokeatzeko.</item> diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml index da5ec73f27b5..6fbe804093eb 100644 --- a/packages/SystemUI/res-keyguard/values-fa/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"برای باز کردن قفل روی «منو» فشار دهید."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"شبکه قفل شد"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"سیمکارت موجود نیست"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"سیمکارت درون رایانهٔ لوحی نیست."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"سیمکارت درون تلفن نیست."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"سیمکارت را وارد کنید."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"سیمکارت موجود نیست یا قابل خواندن نیست. یک سیمکارت وارد کنید."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"سیمکارت غیرقابل استفاده است."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"یک پین ۴ تا ۸ رقمی را تایپ کنید."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"کد پین باید ۸ عدد یا بیشتر باشد."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"کد پین صحیح را دوباره وارد کنید. تلاشهای مکرر بهطور دائم سیمکارت را غیرفعال خواهد کرد."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"کدهای پین منطبق نیستند"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"تلاشهای زیادی برای کشیدن الگو صورت گرفته است"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"پین خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"گذرواژه خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدید. \n\nلطفاً پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، این رایانه لوحی بازنشانی میشود که با آن همه دادههایش حذف میشود."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، تلفن بازنشانی میشود که با آن همه دادههایش حذف میشود."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. این رایانه لوحی بازنشانی میشود که با آن همه دادههایش حذف میشود."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. این تلفن بازنشانی میشود که با آن همه دادههایش حذف میشود."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، این کاربر پاک میشود که با آن همه دادههای کاربر حذف میشود."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، این کاربر پاک میشود که با آن همه دادههای کاربر حذف میشود."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. نمایه کاری پاک میشود که با آن همه دادههای نمایه حذف میشود."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. نمایه کاری پاک میشود که با آن همه دادههای نمایه حذف میشود."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. بعد از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل تلفن را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"کد پین سیمکارت اشتباه است، اکنون برای باز کردن قفل دستگاهتان باید با شرکت مخابراتی تماس بگیرید."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">کد پین سیمکارت اشتباه است، <xliff:g id="NUMBER_1">%d</xliff:g> بار دیگر میتوانید تلاش کنید.</item> diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml index eec3d122159e..6d26e3686dfb 100644 --- a/packages/SystemUI/res-keyguard/values-fi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Poista lukitus painamalla Valikkoa."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Verkko lukittu"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Ei SIM-korttia"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tabletissa ei ole SIM-korttia."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Puhelimessa ei ole SIM-korttia."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Aseta SIM-kortti."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-korttia ei löydy tai ei voi lukea. Aseta SIM-kortti."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM-kortti ei käytettävissä"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Anna 4–8-numeroinen PIN-koodi."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-koodissa tulee olla vähintään 8 numeroa."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Anna uudelleen oikea PUK-koodi. Jos teet liian monta yritystä, SIM-kortti poistetaan käytöstä pysyvästi."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-koodit eivät täsmää"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Liikaa kuvionpiirtoyrityksiä"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Olet kirjoittanut PIN-koodin väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunnin kuluttua."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Olet kirjoittanut salasanan väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunnin kuluttua."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Olet piirtänyt lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunnin kuluttua."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä tabletti nollataan ja kaikki sen tiedot poistetaan."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä käyttäjä ja kaikki sen käyttäjätiedot poistetaan."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä käyttäjä ja kaikki käyttäjän tiedot poistetaan."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen tiedot poistetaan."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen tiedot poistetaan."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan tabletin lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Virheellinen SIM-kortin PIN-koodi. Sinun on nyt otettava yhteys operaattoriin laitteen lukituksen avaamiseksi."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Virheellinen SIM-kortin PIN-koodi. Sinulla on <xliff:g id="NUMBER_1">%d</xliff:g> yritystä jäljellä.</item> diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml index c13ec431d4d8..53255af72e7c 100644 --- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Appuyez sur la touche Menu pour déverrouiller l\'appareil."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Aucune carte SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Aucune carte SIM n\'est insérée dans la tablette."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Aucune carte SIM n\'est insérée dans le téléphone."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insérez une carte SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Carte SIM absente ou illisible. Veuillez insérer une carte SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Carte SIM inutilisable."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Veuillez entrer un NIP comprenant entre quatre et huit chiffres."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Le code PUK doit contenir au moins 8 chiffres."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Veuillez entrer de nouveau le code PUK correct. Trop de tentatives répétées désactiveront définitivement la carte SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Les NIP ne correspondent pas."</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Trop de tentatives."</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Vous avez entré un NIP incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Vous avez entré un mot de passe incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cette tablette sera réinitialisée, ce qui entraînera la suppression de toutes les données qu\'elle contient."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), le téléphone sera réinitialisé, ce qui entraînera la suppression de toutes les données qu\'il contient."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Cette tablette sera réinitialisée, ce qui entraîne la suppression de toutes les données qu\'elle contient."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Ce téléphone sera réinitialisé, ce qui entraîne la suppression de toutes les données qu\'il contient."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cet utilisateur sera supprimé, ce qui entraînera la suppression de toutes ses données."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cet utilisateur sera supprimé, ce qui entraînera la suppression de toutes ses données."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"NIP de carte SIM incorrect. Vous devez maintenant communiquer avec votre fournisseur de services pour déverrouiller votre appareil."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Le NIP de la carte SIM incorrect. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative.</item> diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml index 62d245641ec5..ff3ed5395363 100644 --- a/packages/SystemUI/res-keyguard/values-fr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Appuyez sur \"Menu\" pour déverrouiller le clavier."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Pas de carte SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Aucune carte SIM n\'est insérée dans la tablette."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Aucune carte SIM n\'est insérée dans le téléphone."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insérez une carte SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Carte SIM absente ou illisible. Insérez une carte SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"La carte SIM est inutilisable."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Saisissez un code PIN comprenant 4 à 8 chiffres."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"La clé PUK doit contenir au moins 8 chiffres."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Veuillez saisir de nouveau la clé PUK. Après plusieurs tentatives, la carte SIM sera définitivement désactivée."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Les codes PIN ne correspondent pas"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Trop de tentatives"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Vous avez saisi un code incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nRéessayez dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nRéessayez dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nRéessayez dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, elle sera réinitialisée et toutes les données qu\'elle contient seront supprimées."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, il sera réinitialisé et toutes les données qu\'il contient seront supprimées."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Elle va être réinitialisée et toutes les données qu\'elle contient seront supprimées."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Il va être réinitialisé et toutes les données qu\'il contient seront supprimées."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, ce compte utilisateur et toutes les données associées seront supprimés."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, ce compte utilisateur et toutes les données associées seront supprimés."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Code PIN de la carte SIM incorrect. Vous devez désormais contacter votre opérateur pour déverrouiller votre appareil."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Code PIN de la carte SIM incorrect. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative.</item> diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml index aeef9aaf38e2..d7f6b6a245e2 100644 --- a/packages/SystemUI/res-keyguard/values-gl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Preme Menú para desbloquear."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada pola rede"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Sen tarxeta SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Non hai ningunha tarxeta SIM na tableta."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Non hai ningunha tarxeta SIM no teléfono."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insire unha tarxeta SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Falta a tarxeta SIM ou non se pode ler. Insire unha tarxeta SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Tarxeta SIM inutilizable"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Escribe un PIN que teña entre 4 e 8 números."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"O código PUK debe ter 8 números como mínimo."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Volve introducir o código PUK correcto. Se realizas intentos repetidos é posible que se desactive a tarxeta SIM permanentemente."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN non coinciden"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Tentaches debuxar o padrón moitas veces"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Introduciches o PIN incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Introduciches o contrasinal incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Debuxaches incorrectamente o padrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tentaches desbloquear a tableta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, restablecerase a tableta e, por conseguinte, eliminaranse todos os seus datos."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, restablecerase o teléfono e, por conseguinte, eliminaranse todos os seus datos."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tentaches desbloquear a tableta <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Restablecerase a tableta e, por conseguinte, eliminaranse todos os seus datos."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Restablecerase o teléfono e, por conseguinte, eliminaranse todos os seus datos."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tentaches desbloquear a tableta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, quitarase este usuario e, por conseguinte, todos os datos do usuario."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, quitarase este usuario e, por conseguinte, todos os datos do usuario."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tentaches desbloquear a tableta <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Quitarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Quitarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear a tableta a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"O código PIN da SIM non é correcto. Agora debes contactar co operador para desbloquear o dispositivo."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">O código PIN da SIM é incorrecto. Quédanche <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item> diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml index 3f5cab568ef3..c3b7602adcd6 100644 --- a/packages/SystemUI/res-keyguard/values-gu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"અનલૉક કરવા માટે મેનૂ દબાવો."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"નેટવર્ક લૉક થયું"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"કોઈ સિમ કાર્ડ નથી"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ટૅબ્લેટમાં સિમ કાર્ડ નથી."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ફોનમાં સિમ કાર્ડ નથી."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"એક સિમ કાર્ડ દાખલ કરો."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"સિમ કાર્ડ ખૂટે છે અથવા વાંચન યોગ્ય નથી. સિમ કાર્ડ દાખલ કરો."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"બિનઉપયોગી સિમ કાર્ડ."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 થી 8 સંખ્યાનો હોય તેવો એક પિન લખો."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK કોડ 8 કે તેનાથી વધુ સંખ્યાનો હોવો જોઈએ."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"સાચો PUK કોડ ફરીથી દાખલ કરો. પુનરાવર્તિત પ્રયાસો સિમ ને કાયમી રીતે અક્ષમ કરશે."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"પિન કોડ મેળ ખાતા નથી"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ઘણા બધા પૅટર્ન પ્રયાસો"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"તમારો પિન તમે <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે લખ્યો છે. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"તમારો પાસવર્ડ તમે <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે લખ્યો છે. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> સેકંડમાં ફરીથી પ્રયાસ કરો."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"તમારી અનલૉક પૅટર્ન તમે <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"તમે ટૅબ્લેટને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, આ ટૅબ્લેટ ફરીથી સેટ કરવામાં આવશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"તમે ફોનને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, આ ફોન ફરીથી સેટ કરવામાં આવશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"તમે ટૅબ્લેટને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ ટૅબ્લેટ ફરીથી સેટ થશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"તમે ફોનને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ ફોન ફરીથી સેટ કરાશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"તમે ટૅબ્લેટને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. <xliff:g id="NUMBER_1">%2$d</xliff:g> વધુ અસફળ પ્રયાસો પછી, આ વપરાશકર્તાને દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટાને કાઢી નાખશે."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"તમે ફોનને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, આ વપરાશકર્તાને દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટા કાઢી નાખશે."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"તમે ટૅબ્લેટને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ કાર્યાલયની પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"તમે ફોનને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ કાર્યાલયની પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને એક ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ટૅબ્લેટને અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરી પ્રયાસ કરો."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને ફોન અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ખોટો સિમ પિન કોડ, તમારે હવે તમારું ઉપકરણ અનલૉક કરવા માટે તમારા કૅરીઅરનો સંપર્ક કરવો આવશ્યક છે."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">ખોટો સિમ પિન કોડ, તમારી પાસે <xliff:g id="NUMBER_1">%d</xliff:g> પ્રયાસ બાકી છે.</item> diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml index cc8af317b1d1..1c5ceadd8dd6 100644 --- a/packages/SystemUI/res-keyguard/values-hi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"लॉक खोलने के लिए मेन्यू दबाएं."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लॉक किया हुआ है"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"कोई SIM कार्ड नहीं है"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"टैबलेट में कोई SIM कार्ड नहीं है."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"फ़ोन में कोई SIM कार्ड नहीं है."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM कार्ड लगाएं."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM कार्ड मौजूद नहीं है या उसे पढ़ा नहीं जा सकता है. कोई SIM कार्ड लगाएं."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"बेकार SIM कार्ड."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"कोई ऐसा पिन लिखें, जिसमें 4 से 8 अंक हों."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK कोड 8 या ज़्यादा संख्या वाला होना चाहिए."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"सही PUK कोड दोबारा डालें. बार-बार कोशिश करने से SIM हमेशा के लिए अक्षम हो जाएगा."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"पिन कोड का मिलान नहीं हो रहा है"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"पैटर्न के लिए बहुत ज़्यादा बार कोशिश की गई है"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"आप अपना पिन <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में फिर से कोशिश करें."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"आप अपना पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में फिर से कोशिश करें."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"आपने अपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से ड्रॉ किया है. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में फिर से कोशिश करें."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल कोशिशों के बाद, इस टैबलेट को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल कोशिशों के बाद, इस फ़ोन को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. इस टैबलेट को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. इस फ़ोन को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"आपने टैबलेट का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर, इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा मिट जाएगा."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"आपने फ़ोन का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर, इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा मिट जाएगा."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. वर्क प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. वर्क प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"आपने अपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से ड्रॉ किया है. अगर आपने <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत ड्रॉ किया, तो आपसे अपने टैबलेट को किसी ईमेल खाते का इस्तेमाल करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड बाद फिर से कोशिश करें."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"आपने अपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से ड्रॉ किया है. अगर आपने <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत ड्रॉ किया, तो आपसे अपने फ़ोन को किसी ईमेल खाते का इस्तेमाल करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड बाद फिर से कोशिश करें."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"गलत SIM पिन कोड, अपने डिवाइस को अनलॉक करने के लिए अब आपको अपनी मोबाइल और इंटरनेट सेवा देने वाली कंपनी से संपर्क करना होगा."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">गलत सिम पिन कोड, आप <xliff:g id="NUMBER_1">%d</xliff:g> बार और कोशिश कर सकते हैं.</item> diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml index 17153e48b737..ee7a40350ba2 100644 --- a/packages/SystemUI/res-keyguard/values-hr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pritisnite Izbornik da biste otključali."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nema SIM kartice"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"U tabletu nema SIM kartice."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"U telefonu nema SIM kartice."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Umetnite SIM karticu."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM kartica nedostaje ili nije čitljiva. Umetnite SIM karticu."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM kartica nije upotrebljiva."</string> @@ -84,17 +82,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Unesite PIN koji ima od 4 do 8 brojeva."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kôd treba imati 8 brojeva ili više."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Ponovo unesite ispravan PUK kôd. Ponovljeni pokušaji trajno će onemogućiti SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodovi nisu jednaki"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Previše pokušaja iscrtavanja uzorka"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Netočno ste unijeli PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Netočno ste unijeli zaporku <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja tablet će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja telefon će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER">%d</xliff:g> put/a. Tablet će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> put/a. Telefon će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -103,10 +94,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER">%d</xliff:g> put/a. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> put/a. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati tablet pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Netočan PIN kôd SIM kartice; sada morate kontaktirati svog mobilnog operatera da bi otključao vaš uređaj."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">PIN kôd SIM-a nije točan. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item> diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml index 4eb32e906a7b..2f358a063f46 100644 --- a/packages/SystemUI/res-keyguard/values-hu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"A feloldáshoz nyomja meg a Menü gombot."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Hálózat zárolva"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nincs SIM-kártya"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nincs SIM-kártya a táblagépben."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nincs SIM-kártya a telefonban."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Helyezzen be SIM-kártyát."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"A SIM-kártya hiányzik vagy nem olvasható. Helyezzen be SIM-kártyát."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"A SIM-kártya nem használható."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Írjon be egy 4-8 számjegyű PIN-kódot."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"A PUK-kódnak legalább nyolc számjegyből kell állnia."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Adja meg újra a helyes PUK-kódot. Az ismételt próbálkozásokkal véglegesen letiltja a SIM-kártyát."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"A PIN-kódok nem egyeznek"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Túl sok mintarajzolási próbálkozás"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül adta meg a PIN-kódot.\n\nPróbálja újra <xliff:g id="NUMBER_1">%2$d</xliff:g> másodperc múlva."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül adta meg a jelszót.\n\nPróbálja újra <xliff:g id="NUMBER_1">%2$d</xliff:g> másodperc múlva."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal rosszul rajzolta le a feloldási mintát.\n\nPróbálja újra <xliff:g id="NUMBER_1">%2$d</xliff:g> másodperc múlva."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer visszaállítja a táblagépet, és ezzel az összes adat törlődik róla."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer visszaállítja a telefont, és ezzel az összes adat törlődik róla."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. A rendszer visszaállítja a táblagépet, és ezzel a rajta lévő összes adat törlődik."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer visszaállítja a telefont, és ezzel a rajta lévő összes adat törlődik."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer eltávolítja a felhasználót, és ezzel a felhasználó összes adata törlődik majd."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer eltávolítja a felhasználót, és ezzel a felhasználó összes adata törlődik majd."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. A rendszer eltávolítja a munkaprofilt, és ezzel a profil összes adata törlődik."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer eltávolítja a munkaprofilt, és ezzel a profil összes adata törlődik."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania táblagépét.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania telefonját.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Helytelen PIN-kód a SIM-kártyához. Az eszköz feloldása érdekében, kérjük, vegye fel a kapcsolatot szolgáltatójával."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Helytelen PIN-kód a SIM-kártyához. Még <xliff:g id="NUMBER_1">%d</xliff:g> próbálkozása maradt.</item> diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml index c0d1c93c4999..7da8ed4b8a5b 100644 --- a/packages/SystemUI/res-keyguard/values-hy/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ապակողպելու համար սեղմեք Ընտրացանկը:"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Ցանցը կողպված է"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM քարտ չկա"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Պլանշետում SIM քարտ չկա:"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Հեռախոսում SIM քարտ չկա:"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Տեղադրեք SIM քարտ:"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM քարտը բացակայում է կամ ընթեռնելի չէ: Տեղադրեք SIM քարտ:"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Անպիտան SIM քարտ:"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Մուտքագրեք 4-8 թվանշան պարունակող PIN կոդ։"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK կոդը պետք է առնվազն 8 թվանշան պարունակի։"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Վերամուտքագրեք ճիշտ PUK կոդը: Կրկնվող փորձերը ընդմիշտ կարգելափակեն SIM քարտը:"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN կոդերը չեն համընկնում"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Նախշը մուտքագրելու չափազանց շատ փորձեր են կատարվել"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Դուք սխալ եք մուտքագրել ձեր PIN կոդը <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%2$d</xliff:g> վայրկյանից։"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Դուք սխալ եք մուտքագրել ձեր գաղտնաբառը <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%2$d</xliff:g> վայրկյանից:"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Դուք սխալ եք մուտքագրել ձեր ապակողպման նախշը <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%2$d</xliff:g> վայրկյանից։"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս պլանշետը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս հեռախոսը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Այս պլանշետը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Այս հեռախոսը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Դուք կատարել եք ապակողպման նախշը մուտքագրելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել պլանշետը էլփոստի հաշվի միջոցով։\n\n Խնդրում ենք փորձել կրկին <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Դուք կատարել եք ապակողպման նախշը մուտքագրելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել հեռախոսը էլփոստի հաշվի միջոցով։\n\n Խնդրում ենք փորձել կրկին <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM PIN կոդը սխալ է։ Այժմ պետք է դիմեք ձեր օպերատորին՝ սարքն արգելահանելու համար:"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item> diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml index 8772d8977331..406b00e6e369 100644 --- a/packages/SystemUI/res-keyguard/values-in/strings.xml +++ b/packages/SystemUI/res-keyguard/values-in/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Tekan Menu untuk membuka kunci."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Jaringan terkunci"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Tidak ada kartu SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tidak ada kartu SIM dalam tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Tidak ada Kartu SIM di dalam ponsel."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Masukkan kartu SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Kartu SIM tidak ada atau tidak dapat dibaca. Masukkan kartu SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Kartu SIM tidak dapat digunakan."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Ketikkan PIN berupa 4 sampai 8 angka."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Kode PUK harus terdiri dari 8 angka atau lebih."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Masukkan kembali kode PUK yang benar. Jika berulang kali gagal, SIM akan dinonaktifkan secara permanen."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kode PIN tidak cocok"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Terlalu banyak upaya pola"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah mengetik PIN. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> detik."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah mengetik sandi. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> detik."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> detik."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, tablet ini akan disetel ulang, sehingga semua datanya akan dihapus."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, ponsel ini akan disetel ulang, sehingga semua datanya akan dihapus."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Tablet ini akan disetel ulang, sehingga menghapus semua datanya."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Ponsel ini akan disetel ulang, sehingga menghapus semua datanya."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Profil kerja akan dihapus, sehingga menghapus semua data profil."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Profil kerja akan dihapus, sehingga menghapus semua data profil."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka. Setelah gagal <xliff:g id="NUMBER_1">%2$d</xliff:g> kali lagi, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka. Setelah gagal <xliff:g id="NUMBER_1">%2$d</xliff:g> kali lagi, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Kode PIN SIM salah. Hubungi operator untuk membuka kunci perangkat."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Kode PIN SIM salah, sisa, sisa <xliff:g id="NUMBER_1">%d</xliff:g> percobaan.</item> diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml index bece62548cb1..4f87df6bb68e 100644 --- a/packages/SystemUI/res-keyguard/values-is/strings.xml +++ b/packages/SystemUI/res-keyguard/values-is/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ýttu á valmyndarhnappinn til að taka úr lás."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Net læst"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Ekkert SIM-kort"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Ekkert SIM-kort í spjaldtölvunni."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Ekkert SIM-kort í símanum."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Settu SIM-kort í."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-kort vantar eða það er ekki læsilegt. Settu SIM-kort í."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Ónothæft SIM-kort."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Sláðu in PIN-númer sem er 4 til 8 tölustafir."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-númerið verður að vera 8 tölustafir eða lengra."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Prófaðu aftur að setja inn rétt PUK-númer. Endurteknar tilraunir gera SIM-kortið varanlega óvirkt."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-númerin stemma ekki"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Of margar tilraunir til að teikna mynstur"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Þú hefur slegið inn rangt PIN-númer <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> sekúndur."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Þú hefur slegið inn rangt aðgangsorð <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> sekúndur."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> sekúndur."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður spjaldtölvan endurstillt, með þeim afleiðingum að öllum gögnum hennar verður eytt."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður síminn endurstilltur, með þeim afleiðingum að öllum gögnum hans verður eytt."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Spjaldtölvan verður endurstillt, með þeim afleiðingum að öllum gögnum hennar verður eytt."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Síminn verður endurstilltur, með þeim afleiðingum að öllum gögnum hans verður eytt."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður notandinn fjarlægður með þeim afleiðingum að öllum notandagögnum verður eytt."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður notandinn fjarlægður með þeim afleiðingum að öllum notandagögnum verður eytt."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna spjaldtölvuna með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verðurðu beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Rangt PIN-númer SIM-korts. Nú þarftu að hafa samband við símafyrirtækið til að opna fyrir tækið."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Rangt PIN-númer SIM-korts. Þú átt <xliff:g id="NUMBER_1">%d</xliff:g> tilraun eftir.</item> diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml index cd27ba4d7b0e..f714bf7cfde7 100644 --- a/packages/SystemUI/res-keyguard/values-it/strings.xml +++ b/packages/SystemUI/res-keyguard/values-it/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Premi Menu per sbloccare."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rete bloccata"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nessuna SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nessuna scheda SIM presente nel tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nessuna scheda SIM presente nel telefono."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Inserisci una scheda SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Scheda SIM mancante o non leggibile. Inserisci una scheda SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Scheda SIM inutilizzabile."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Il PIN deve essere di 4-8 numeri."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Il codice PUK dovrebbe avere almeno otto numeri."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Inserisci di nuovo il codice PUK corretto. Ripetuti tentativi comportano la disattivazione definitiva della scheda SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"I codici PIN non corrispondono"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Troppi tentativi di inserimento della sequenza"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Hai digitato la tua password <xliff:g id="NUMBER_0">%1$d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, il tablet verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, il telefono verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il tablet verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il telefono verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Codice PIN della SIM errato. Devi contattare l\'operatore per sbloccare il dispositivo."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione.</item> diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml index d7156370a686..2af519224c2d 100644 --- a/packages/SystemUI/res-keyguard/values-iw/strings.xml +++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"לחץ על \'תפריט\' כדי לבטל את הנעילה."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"הרשת נעולה"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"אין כרטיס SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"אין כרטיס SIM בטאבלט."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"אין כרטיס SIM בטלפון."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"הכנס כרטיס SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"כרטיס ה-SIM חסר או שלא ניתן לקרוא אותו. הכנס כרטיס SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"לא ניתן להשתמש בכרטיס SIM זה."</string> @@ -85,17 +83,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"הקלד קוד גישה שאורכו 4 עד 8 ספרות."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"קוד PUK צריך להיות בן 8 ספרות או יותר."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"הזן את קוד ה-PUK הנכון. ניסיונות חוזרים ישביתו את כרטיס ה-SIM לצמיתות."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"קודי הגישה אינם תואמים"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ניסית לשרטט את קו ביטול הנעילה יותר מדי פעמים"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"הקלדת קוד גישה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. \n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%2$d</xliff:g> שניות."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"הקלדת סיסמה שגויה <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים.\n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%2$d</xliff:g> שניות."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. \n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%2$d</xliff:g> שניות."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, טאבלט זה יאופס וכל הנתונים שבו יימחקו."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, טלפון זה יאופס וכל הנתונים שבו יימחקו."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER">%d</xliff:g> פעמים. הטאבלט יאופס וכל הנתונים שלו יימחקו."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים. הטלפון יאופס וכל הנתונים שבו יימחקו."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, משתמש זה יוסר וכל נתוני המשתמש יימחקו."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, משתמש זה יוסר וכל נתוני המשתמש יימחקו."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -104,10 +95,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER">%d</xliff:g> פעמים. פרופיל העבודה יוסר וכל נתוני הפרופיל יימחקו."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים. פרופיל העבודה יוסר וכל נתוני הפרופיל יימחקו."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטאבלט באמצעות חשבון אימייל.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטלפון באמצעות חשבון אימייל.\n\n נסה שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"קוד הגישה של כרטיס ה-SIM שגוי. צור קשר עם הספק כדי לבטל את נעילת המכשיר."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="two">קוד הגישה של כרטיס ה-SIM שגוי. נותרו לך עוד <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות.</item> diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml index 3ed6fecf27dd..5f0d83fb81bc 100644 --- a/packages/SystemUI/res-keyguard/values-ja/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"メニューからロックを解除できます。"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"ネットワークがロックされました"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM カードなし"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"タブレットに SIM カードが挿入されていません。"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"スマートフォンに SIM カードが挿入されていません。"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM カードを挿入してください。"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM カードが見つからないか読み取れません。SIM カードを挿入してください。"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM カードは使用できません。"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"PIN は 4~8 桁の数字で入力してください。"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK コードは 8 桁以下の数字で入力してください。"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"正しい PUK コードを再入力してください。誤入力を繰り返すと、SIM が完全に無効になる恐れがあります。"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN コードが一致しません"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"パターンの入力を所定の回数以上間違えました"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN の入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。\n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後にもう一度お試しください。"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"パスワードの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。\n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後にもう一度お試しください。"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。\n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後にもう一度お試しください。"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"タブレットのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このタブレットはリセットされ、データはすべて消去されます。"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"スマートフォンのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このスマートフォンはリセットされ、データはすべて消去されます。"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"タブレットのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。このタブレットはリセットされ、データはすべて消去されます。"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"スマートフォンのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。このスマートフォンはリセットされ、データはすべて消去されます。"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"タブレットのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このユーザーは削除され、ユーザー データはすべて消去されます。"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"スマートフォンのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このユーザーは削除され、ユーザー データはすべて消去されます。"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"タブレットのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。仕事用プロファイルは削除され、プロファイルのデータはすべて消去されます。"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"スマートフォンのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。仕事用プロファイルは削除され、プロファイルのデータはすべて消去されます。"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、タブレットのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、スマートフォンのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM PIN コードが無効です。お使いのデバイスをロック解除するには携帯通信会社にお問い合わせいただく必要があります。"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM PIN コードが無効です。入力できるのはあと <xliff:g id="NUMBER_1">%d</xliff:g> 回です。</item> diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml index cf170e4a8bd7..cd1719b16922 100644 --- a/packages/SystemUI/res-keyguard/values-ka/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"განსაბლოკად დააჭირეთ მენიუს."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"ქსელი ჩაკეტილია"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM ბარათი არ არის"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ტაბლეტში არ არის SIM ბარათი."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ტელეფონში არ არის SIM ბარათი."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ჩადეთ SIM ბარათი."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM ბარათი არ არის ან არ იკითხება. ჩადეთ SIM ბარათი."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM ბარათი გამოუსადეგარია."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"აკრიფეთ 4-8 ციფრისგან შემდგარი PIN-კოდი."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-კოდი 8 ან მეტი ციფრისგან უნდა შედგებოდეს."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"ხელახლა შეიყვანეთ სწორი PUK-კოდი. რამდენიმე წარუმატებელი მცდელობის შემთხვევაში, SIM ბარათი სამუდამოდ გამოუსადეგარი გახდება."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-კოდები არ ემთხვევა"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ნიმუში დახატულია არასწორად მეტისმეტად ბევრჯერ"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"თქვენ არასწორად შეიყვანეთ PIN-კოდი <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. \n\nცადეთ ხელახლა <xliff:g id="NUMBER_1">%2$d</xliff:g> წამში."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"თქვენ არასწორად აკრიფეთ პაროლი <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. \n\nცადეთ ხელახლა <xliff:g id="NUMBER_1">%2$d</xliff:g> წამში."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"თქვენ არასწორად დახატეთ განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. \n\nცადეთ ხელახლა <xliff:g id="NUMBER_1">%2$d</xliff:g> წამში."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამ ტაბლეტის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამ ტელეფონის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, ამ ტაბლეტის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, ამ ტელეფონის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ეს მომხმარებელი ამოიშლება, რაც მომხმარებლის ყველა მონაცემის წაშლას გამოიწვევს."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ეს მომხმარებელი ამოიშლება, რაც მომხმარებლის ყველა მონაცემის წაშლას გამოიწვევს."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, სამსახურის პროფილი ამოიშლება, რაც პროფილის ყველა მონაცემის წაშლას გამოიწვევს."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, სამსახურის პროფილი ამოიშლება, რაც პროფილის ყველა მონაცემის წაშლას გამოიწვევს."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ტაბლეტის განბლოკვა თქვენი ელფოსტის ანგარიშის მეშვეობით მოგიწევთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ტელეფონის განბლოკვა თქვენი ელფოსტის ანგარიშის მეშვეობით მოგიწევთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM ბარათის PIN-კოდი არასწორია. ახლა თქვენი მოწყობილობის განსაბლოკად თქვენს ოპერატორთან დაკავშირება მოგიწევთ."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM ბარათის PIN-კოდი არასწორია. თქვენ დაგრჩათ <xliff:g id="NUMBER_1">%d</xliff:g> მცდელობა.</item> diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml index 53c11386f247..0b78b579786e 100644 --- a/packages/SystemUI/res-keyguard/values-kk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ашу үшін \"Мәзір\" пернесін басыңыз."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Желі құлыптаулы"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM картасы салынбаған"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Планшетте SIM картасы жоқ."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Телефонда SIM картасы жоқ."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM картасын енгізіңіз."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM картасы жоқ немесе оқылмайды. SIM картасын салыңыз."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM картасы қолданыстан шыққан."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4-8 саннан тұратын PIN кодын енгізіңіз."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK коды 8 не одан көп саннан тұруы қажет."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Дұрыс PUK кодын қайта енгізіңіз. Әрекетті қайталай берсеңіз, SIM картасы өшіріледі."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN коды сәйкес келмейді"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Тым көп өрнек енгізу әрекеті жасалды"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN коды <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундтан кейін әркетті қайталаңыз."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Құпия сөз <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Планшет құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін осы планшет бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Телефон құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін осы телефон бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Планшет құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Осы планшет бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Телефон құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Осы телефон бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Планшет құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін пайдаланушы өшіріліп, оның бүкіл деректері жойылады."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Телефон құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін пайдаланушы өшіріліп, оның бүкіл деректері жойылады."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Планшет құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Жұмыс профилі өшіріліп, оның бүкіл деректері жойылады."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Телефон құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Жұмыс профилі өшіріліп, оның бүкіл деректері жойылады."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін планшетті есептік жазба арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін телефонды есептік жазба арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM PIN коды дұрыс емес, операторға хабарласып, құрылғының құлпын ашуды сұраңыз."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM PIN коды дұрыс емес. <xliff:g id="NUMBER_1">%d</xliff:g> әрекет қалды.</item> diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml index 0e4b418f2bc2..a07c299dda49 100644 --- a/packages/SystemUI/res-keyguard/values-km/strings.xml +++ b/packages/SystemUI/res-keyguard/values-km/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ចុចម៉ឺនុយ ដើម្បីដោះសោ។"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"បណ្ដាញជាប់សោ"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"គ្មានស៊ីមកាតទេ"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"គ្មានស៊ីមកាតនៅក្នុងថេប្លេតទេ។"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"គ្មានស៊ីមកាតនៅក្នុងទូរសព្ទទេ។"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ស៊កបញ្ចូលស៊ីមកាត។"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ស៊ីមកាតបានបាត់ ឬមិនអាចអានបាន។ សូមស៊កបញ្ចូលស៊ីមកាត។"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ស៊ីមកាតមិនអាចប្រើបានទេ។"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"វាយបញ្ចូលកូដ PIN ចន្លោះពី 4 ទៅ 8 ខ្ទង់"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"កូដ PUK គួរតែមានលេខ 8 ខ្ទង់ ឬច្រើនជាងនេះ។"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"សូមបញ្ចូលកូដ PUK ម្ដងទៀត។ ការព្យាយាមដដែលច្រើនដងនឹងបិទដំណើរការស៊ីមនេះជាអចិន្ត្រៃយ៍។"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"កូដ PIN មិនត្រូវគ្នាទេ"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ការព្យាយាមបញ្ចូលលំនាំច្រើនដងពេកហើយ"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"អ្នកបានវាយបញ្ចូលកូដ PIN របស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ \n\nសូមព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_1">%2$d</xliff:g> វិនាទីទៀត។"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"អ្នកបានវាយបញ្ចូលពាក្យសម្ងាត់របស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ \n\nសូមព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_1">%2$d</xliff:g> វិនាទីទៀត។"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ \n\nសូមព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_1">%2$d</xliff:g> វិនាទីទៀត។"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"អ្នកបានព្យាយាមដោះសោថេប្លេតនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ ប្រសិនបើការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យទេ ថេប្លេតនេះនឹងត្រូវបានកំណត់ឡើងវិញ ហើយវានឹងលុបទិន្នន័យរបស់វាទាំងអស់។"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"អ្នកបានព្យាយាមដោះសោទូរសព្ទនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ ប្រសិនបើការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យទេ ទូរសព្ទនេះនឹងត្រូវបានកំណត់ឡើងវិញ ហើយវានឹងលុបទិន្នន័យរបស់វាទាំងអស់។"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"អ្នកបានព្យាយាមដោះសោថេប្លេតនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង។ ថេប្លេតនេះនឹងត្រូវបានកំណត់ឡើងវិញ ហើយវានឹងលុបទិន្នន័យទាំងអស់របស់វា។"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"អ្នកបានព្យាយាមដោះសោទូរសព្ទនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដងហើយ។ ទូរសព្ទនេះនឹងត្រូវបានកំណត់ឡើងវិញ ហើយវានឹងលុបទិន្នន័យទាំងអស់របស់វា។"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"អ្នកបានព្យាយាមដោះសោថេប្លេតនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ ប្រសិនបើការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យទេ អ្នកប្រើប្រាស់នេះនឹងត្រូវបានលុប ហើយវានឹងលុបទិន្នន័យរបស់អ្នកប្រើប្រាស់ទាំងអស់។"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"អ្នកបានព្យាយាមដោះសោទូរសព្ទនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ ប្រសិនបើការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យទេ អ្នកប្រើប្រាស់នេះនឹងត្រូវបានលុប ហើយវានឹងលុបទិន្នន័យរបស់អ្នកប្រើប្រាស់ទាំងអស់។"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"អ្នកបានព្យាយាមដោះសោថេប្លេតនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដងហើយ។ កម្រងព័ត៌មានការងារនេះនឹងត្រូវបានលុប ហើយវានឹងលុបទិន្នន័យកម្រងព័ត៌មានទាំងអស់។"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"អ្នកបានព្យាយាមដោះសោទូរសព្ទនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដងហើយ។ កម្រងព័ត៌មានការងារនេះនឹងត្រូវបានលុប ហើយវានឹងលុបទិន្នន័យកម្រងព័ត៌មានទាំងអស់។"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ ប្រសិនបើការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យទេ អ្នកនឹងត្រូវបានស្នើឲ្យដោះសោថេប្លេតរបស់អ្នក ដោយប្រើគណនីអ៊ីមែល។\n\n សូមព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទីទៀត។"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ ប្រសិនបើការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យទេ អ្នកនឹងត្រូវបានស្នើឲ្យដោះសោទូរសព្ទរបស់អ្នក ដោយប្រើគណនីអ៊ីមែល។\n\n សូមព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទីទៀត។"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"កូដ PIN របស់ស៊ីមមិនត្រឹមត្រូវទេ អ្នកត្រូវទាក់ទងទៅក្រុមហ៊ុនបម្រើសេវាទូរសព្ទរបស់អ្នកឥឡូវនេះ ដើម្បីដោះសោឧបករណ៍របស់អ្នក។"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">កូដ PIN របស់ស៊ីមមិនត្រឹមត្រូវទេ អ្នកអាចព្យាយាមបាន <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត។</item> diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml index 1d162e82da22..2c88419a1cba 100644 --- a/packages/SystemUI/res-keyguard/values-kn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ಅನ್ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"ನೆಟ್ವರ್ಕ್ ಲಾಕ್ ಆಗಿದೆ"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ಸಿಮ್ ಕಾರ್ಡ್ ಇಲ್ಲ"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ಟ್ಯಾಬ್ಲೆಟ್ನಲ್ಲಿ ಸಿಮ್ ಕಾರ್ಡ್ ಇಲ್ಲ."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ಪೋನ್ನಲ್ಲಿ ಯಾವುದೇ ಸಿಮ್ ಕಾರ್ಡ್ ಇಲ್ಲ."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ಸಿಮ್ ಕಾರ್ಡ್ ಸೇರಿಸಿ."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ಸಿಮ್ ಕಾರ್ಡ್ ಇಲ್ಲ ಅಥವಾ ಗುರುತಿಸಲು ಅಸಾಧ್ಯ. ಒಂದು ಸಿಮ್ ಕಾರ್ಡ್ ಸೇರಿಸಿ."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ನಿಷ್ಪ್ರಯೋಜಕ ಸಿಮ್ ಕಾರ್ಡ್."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 ರಿಂದ 8 ಸಂಖ್ಯೆಗಳಿರುವ ಪಿನ್ ಟೈಪ್ ಮಾಡಿ."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK ಕೋಡ್ 8 ಅಥವಾ ಹೆಚ್ಚು ಸಂಖ್ಯೆಗಳನ್ನು ಹೊಂದಿರಬೇಕು."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"ಸರಿಯಾದ PUK ಕೋಡ್ ಮರು-ನಮೂದಿಸಿ. ಸತತ ಪ್ರಯತ್ನಗಳು ಸಿಮ್ ಅನ್ನು ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ಪಿನ್ ಕೋಡ್ಗಳು ಹೊಂದಾಣಿಕೆಯಾಗುತ್ತಿಲ್ಲ"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ಪ್ಯಾಟರ್ನ್ ಪ್ರಯತ್ನಗಳ ಮಿತಿ ಮುಗಿದಿದೆ"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"ನಿಮ್ಮ ಪಿನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಟೈಪ್ ಮಾಡಿದ್ದೀರಿ. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"ನಿಮ್ಮ ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ನಮೂದಿಸಿದ್ದೀರಿ. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಎಳೆದಿದ್ದೀರಿ. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಫೋನ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ಫೋನ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಫೋನ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ಫೋನ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಎಳೆದಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಎಳೆದಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ಫೋನ್ ಅನ್ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ಸಿಮ್ ಪಿನ್ ಕೋಡ್ ತಪ್ಪಾಗಿದೆ, ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು ಈ ಕೂಡಲೇ ನಿಮ್ಮ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಬೇಕು."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">ಸಿಮ್ ಪಿನ್ ಕೋಡ್ ತಪ್ಪಾಗಿದೆ, ನಿಮಗೆ <xliff:g id="NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ.</item> diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml index c0fb7163aeb7..bdbd3d99ce06 100644 --- a/packages/SystemUI/res-keyguard/values-ko/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"잠금 해제하려면 메뉴를 누르세요."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"네트워크 잠김"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM 카드 없음"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"태블릿에 SIM 카드가 없습니다."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"휴대전화에 SIM 카드가 없습니다."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM 카드를 삽입하세요."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM 카드가 없거나 읽을 수 없는 상태입니다. SIM 카드를 삽입하세요."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"사용할 수 없는 SIM 카드입니다."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4~8자리 숫자로 된 PIN을 입력하세요."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK 코드는 8자리 이상의 숫자여야 합니다."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"올바른 PUK 코드를 다시 입력하세요. 입력을 반복해서 시도하면 SIM이 영구적으로 사용 중지됩니다."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 코드가 일치하지 않음"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"패턴 그리기를 너무 많이 시도함"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN을 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 입력했습니다. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>초 후에 다시 시도하세요."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"비밀번호를 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 입력했습니다. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>초 후에 다시 시도하세요."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 그렸습니다. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>초 후에 다시 시도하세요."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"태블릿 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 태블릿이 재설정되며 모든 데이터가 삭제됩니다."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 휴대전화가 재설정되며 모든 데이터가 삭제됩니다."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"태블릿 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 태블릿이 재설정되며 모든 데이터가 삭제됩니다."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 휴대전화가 재설정되며 모든 데이터가 삭제됩니다."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"태블릿 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이 사용자와 모든 사용자 데이터가 삭제됩니다."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이 사용자와 모든 사용자 데이터가 삭제됩니다."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"태블릿 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필과 모든 프로필 데이터가 삭제됩니다."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필과 모든 프로필 데이터가 삭제됩니다."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금 해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금 해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"잘못된 SIM PIN코드입니다. 이동통신사에 문의하여 기기를 잠금 해제해야 합니다."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">잘못된 SIM PIN 코드입니다. 입력을 <xliff:g id="NUMBER_1">%d</xliff:g>번 더 시도할 수 있습니다.</item> diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml index 32a334645cef..8e9c794ad095 100644 --- a/packages/SystemUI/res-keyguard/values-ky/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Кулпуну ачуу үчүн Менюну басыңыз."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Тармак кулпуланган"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM карта жок"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Планшетте SIM-карта жок."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Телефондо SIM-карта жок."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM-карта салыңыз."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-карта жок же ал окулбай калган. SIM-карта салыңыз."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Жараксыз SIM-карта."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4–8 сандан турган PIN-кодду териңиз."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-код 8 же андан көп сандан турушу керек."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"PUK-кодду кайрадан туура киргизиңиз. Кайталанган аракеттер SIM-картаны биротоло жараксыз кылат."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коддор дал келген жок"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Өтө көп графикалык ачкычты тартуу аракети болду"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN-кодуңузду <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Сырсөзүңүздү <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Кулпуну ачуучу графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Планшеттин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул планшет баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул телефон баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Бул планшет баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет жасадыңыз. Бул телефон баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Планшеттин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили чыгарылып салынып, андагы бардык дайындар жок болот."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили чыгарылып салынып, андагы бардык дайындар жок болот."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Сиз графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин планшетиңизди бөгөттөн электрондук почтаңыз аркылуу чыгарышыңыз талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Сиз графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин телефонуңузду бөгөттөн электрондук почтаңыз аркылуу чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM-картанын PIN-коду туура эмес. Эми түзмөктү бөгөттөн чыгаруу үчүн байланыш операторуңузга кайрылышыңыз керек."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM-картанын PIN-коду туура эмес, сизде <xliff:g id="NUMBER_1">%d</xliff:g> аракет калды.</item> diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml index 36830025462e..3ae088bcf914 100644 --- a/packages/SystemUI/res-keyguard/values-lo/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ກົດ \"ເມນູ\" ເພື່ອປົດລັອກ."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"ເຄືອຂ່າຍຖືກລັອກ"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ບໍ່ມີຊິມກາດ"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ບໍ່ມີຊິມກາດໃນແທັບເລັດ."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ບໍ່ມີ SIM card ໃນໂທລະສັບ."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ໃສ່ຊິມກາດ."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ບໍ່ພົບເຫັນຊິມກາດ ຫຼືບໍ່ສາມາດອ່ານຊິມກາດໄດ້. ກະລຸນາໃສ່ຊິມກາດໃໝ່."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM card ບໍ່ສາມາດໃຊ້ໄດ້."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"ພິມລະຫັດ PIN ທີ່ມີ 4 ຫາ 8 ໂຕເລກ."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"ລະຫັດ PUK ຄວນມີຢ່າງໜ້ອຍ 8 ໂຕເລກ."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"ປ້ອນລະຫັດ PUK ທີ່ຖືກຕ້ອງຄືນໃໝ່. ການພະຍາຍາມໃສ່ຫຼາຍເທື່ອຈະເຮັດໃຫ້ຊິມກາດໃຊ້ບໍ່ໄດ້ຖາວອນ."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ລະຫັດ PIN ບໍ່ກົງກັນ"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ແຕ້ມຮູບແບບປົດລັອກຫຼາຍເກີນໄປ"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"ທ່ານພິມລະຫັດ PIN ຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. \n\nກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ວິນາທີ."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"ທ່ານພິມລະຫັດຜ່ານຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. \n\nໃຫ້ລອງໃໝ່ອີກຄັ້ງໃນອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ວິນາທີ."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"ທ່ານແຕ້ມຮູບແບບປົດລັອກບໍ່ຖືກ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. \n\nລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ວິນາທີ."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ຄັ້ງ, ແທັບເລັດນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ຄັ້ງ, ໂທລະສັບນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ແທັບເລັດນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂທລະສັບນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g>ຄັ້ງ, ຜູ້ໃຊ້ນີ້ຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຜູ້ໃຊ້."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ຄັ້ງ, ຜູ້ໃຊ້ນີ້ຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຜູ້ໃຊ້."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກແທັບເລັດຂອງທ່ານ ດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ອີເມວຂອງທ່ານ.\n\n ກະລຸນາລອງໃໝ່ອີກຄັ້ງໃນອີກ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍບັນຊີອີເມວ.\n\n ລອງໃໝ່ອີກຄັ້ງໃນ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ລະຫັດ PIN ຂອງ SIM ບໍ່ຖືກຕ້ອງທ່ານຕ້ອງຕິດຕໍ່ຫາຜູ່ໃຫ້ບໍລິການ ເພື່ອປົດລັອກອຸປະກອນຂອງທ່ານ."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">ລະຫັດ SIM PIN ບໍ່ຖືກຕ້ອງ, ທ່ານຍັງພະຍາຍາມໄດ້ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ.</item> diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml index 49812ce1b9d5..3d637f0e7113 100644 --- a/packages/SystemUI/res-keyguard/values-lt/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Paspauskite meniu, jei norite atrakinti."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Tinklas užrakintas"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nėra SIM kortelės"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planšetiniame kompiuteryje nėra SIM kortelės."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefone nėra SIM kortelės."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Įdėkite SIM kortelę."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Nėra SIM kortelės arba ji neskaitoma. Įdėkite SIM kortelę."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Negalima naudoti SIM kortelės."</string> @@ -85,17 +83,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Įveskite PIN kodą, sudarytą iš 4–8 skaičių."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kodas turėtų būti sudarytas iš 8 ar daugiau skaitmenų."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Pakartotinai įveskite tinkamą PUK kodą. Pakartotinai bandant SIM kortelė bus išjungta visam laikui."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodai nesutampa"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Per daug atrakinimo piešinių bandymų"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai įvedėte PIN kodą. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai įvedėte slaptažodį. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis planšetinis kompiuteris bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Šis planšetinis kompiuteris bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Šis telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -104,10 +95,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Netinkamas SIM kortelės PIN kodas. Reikės susisiekti su operatoriumi, kad atrakintų įrenginį."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Netinkamas SIM kortelės PIN kodas. Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymas.</item> diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml index 94244ac430e5..2c24f4ad2718 100644 --- a/packages/SystemUI/res-keyguard/values-lv/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Lai atbloķētu, nospiediet izvēlnes ikonu."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Tīkls ir bloķēts."</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nav SIM kartes."</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planšetdatorā nav SIM kartes."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Tālrunī nav SIM kartes."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Ievietojiet SIM karti."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Nav SIM kartes, vai arī to nevar nolasīt. Ievietojiet SIM karti."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Nelietojama SIM karte."</string> @@ -84,17 +82,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Ievadiet PIN kodu, kas sastāv no 4 līdz 8 cipariem."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kodam ir jābūt vismaz 8 ciparus garam."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Atkārtoti ievadiet pareizo PUK kodu. Ja vairākas reizes ievadīsiet to nepareizi, SIM karte tiks neatgriezeniski atspējota."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodi neatbilst."</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Pārāk daudz kombinācijas mēģinājumu"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) esat ievadījis nepareizu PIN kodu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundes(-ēm)."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) esat ievadījis nepareizu paroli.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundes(-ēm)."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) esat nepareizi uzzīmējis atbloķēšanas kombināciju.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundes(-ēm)."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis planšetdators tiks atiestatīts, kā arī visi planšetdatora dati tiks dzēsti."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis tālrunis tiks atiestatīts, kā arī visi tālruņa dati tiks dzēsti."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Šis planšetdators tiks atiestatīts, kā arī visi planšetdatora dati tiks dzēsti."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Šis tālrunis tiks atiestatīts, kā arī visi tālruņa dati tiks dzēsti."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -103,10 +94,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Nepareizs SIM kartes PIN kods. Lai atbloķētu ierīci, sazinieties ar mobilo sakaru operatoru."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="zero">Nepareizs SIM kartes PIN kods. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizes.</item> diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml index 52528f75ec87..d434bc4a1200 100644 --- a/packages/SystemUI/res-keyguard/values-mk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Притиснете „Мени“ за отклучување."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежата е заклучена"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Нема SIM-картичка"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Во таблетот нема SIM-картичка."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Во телефонот нема SIM-картичка."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Вметнете SIM-картичка."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Нема SIM-картичка или не може да се прочита. Вметнете SIM-картичка."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Неупотреблива SIM-картичка."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Внесете PIN што содржи 4 - 8 броеви."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-кодот треба да содржи 8 или повеќе броеви."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Повторно внесете го точниот PUK-код. Повторните обиди трајно ќе ја оневозможат SIM-картичката."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-кодовите не се совпаѓаат"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Премногу обиди со шема"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Погрешно сте го напишале вашиот PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунди."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Погрешно сте ја напишале вашата лозинка <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунди."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Погрешно сте ја нацртале вашата шема за отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунди."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, таблетот ќе се ресетира, со што ќе се избришат сите негови податоци."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, телефонот ќе се ресетира, со што ќе се избришат сите негови податоци."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER">%d</xliff:g> пати. Овој таблет ќе се ресетира, со што ќе се избришат сите негови податоци."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Овој телефон ќе се ресетира, со што ќе се избришат сите негови податоци."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, корисникот ќе се отстрани, со што ќе се избришат сите негови податоци."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, корисникот ќе се отстрани, со што ќе се избришат сите податоци на корисникот."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите таблетот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите телефонот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Погрешен PIN-код за SIM, сега мора да контактирате со вашиот оператор за да го отклучите уредот."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Погрешен PIN-код за SIM, ви преостанува уште <xliff:g id="NUMBER_1">%d</xliff:g> обид.</item> diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml index 5f3a8ca882c5..3992e17a8757 100644 --- a/packages/SystemUI/res-keyguard/values-ml/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"അൺലോക്കുചെയ്യാൻ മെനു അമർത്തുക."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"നെറ്റ്വർക്ക് ലോക്കുചെയ്തു"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"സിം കാർഡില്ല"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ടാബ്ലെറ്റിൽ സിം കാർഡൊന്നുമില്ല."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ഫോണിൽ സിം കാർഡൊന്നുമില്ല."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ഒരു സിം കാർഡ് ഇടുക."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"സിം കാർഡ് കാണുന്നില്ല, അല്ലെങ്കിൽ റീഡുചെയ്യാനായില്ല. ഒരു സിം കാർഡ് ഇടുക."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ഉപയോഗയോഗ്യമല്ലാത്ത സിം കാർഡ്."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 മുതൽ 8 വരെ അക്കങ്ങളുള്ള ഒരു പിൻ ടൈപ്പുചെയ്യുക."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK കോഡിൽ 8 അല്ലെങ്കിൽ അതിലധികം സംഖ്യകൾ ഉണ്ടായിരിക്കണം."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"ശരിയായ PUK കോഡ് വീണ്ടും നൽകുക. ആവർത്തിച്ചുള്ള ശ്രമങ്ങൾ സിം ശാശ്വതമായി പ്രവർത്തനരഹിതമാക്കും."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"പിൻ കോഡുകൾ പൊരുത്തപ്പെടുന്നില്ല"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"വളരെയധികം പാറ്റേൺ ശ്രമങ്ങൾ"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ പിൻ തെറ്റായി ടൈപ്പുചെയ്തു. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> സെക്കന്റിനുശേഷം വീണ്ടും ശ്രമിക്കുക."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ നിങ്ങളുടെ പാസ്വേഡ് തെറ്റായി ടൈപ്പുചെയ്തു. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> സെക്കന്റിനുശേഷം വീണ്ടും ശ്രമിക്കുക."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ അൺലോക്ക് പാറ്റേൺ തെറ്റായി വരച്ചു. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> സെക്കന്റിനുശേഷം വീണ്ടും ശ്രമിക്കുക."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ടാബ്ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഈ ടാബ്ലെറ്റ് റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ ഈ ഫോൺ റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ടാബ്ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഈ ഫോൺ റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഈ ഫോൺ റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ടാബ്ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ ഈ ഉപയോക്താവിനെ നീക്കം ചെയ്യുകയും, അതുവഴി ഉപയോക്താവിന്റെ എല്ലാ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ ഈ ഉപയോക്താവിനെ നീക്കം ചെയ്യുകയും, അതുവഴി ഉപയോക്താവിന്റെ എല്ലാ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ടാബ്ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യപ്പെടുകയും, അതുവഴി എല്ലാ പ്രൊഫൈൽ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യപ്പെടുകയും, അതുവഴി എല്ലാ പ്രൊഫൈൽ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ടാബ്ലെറ്റ് അൺലോക്കുചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ശ്രമിക്കുക."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ഫോൺ അൺലോക്കുചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ശ്രമിക്കുക."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"സിം പിൻ കോഡ് തെറ്റാണ്, നിങ്ങളുടെ ഉപകരണം അൺലോക്കുചെയ്യാൻ ഇനി നിങ്ങളുടെ കാരിയറുമായി ബന്ധപ്പെടണം."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">സിം പിൻ കോഡ് തെറ്റാണ്, നിങ്ങൾക്ക് <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ശേഷിക്കുന്നു.</item> diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml index 6eda5d800ccd..ba80daf7ece4 100644 --- a/packages/SystemUI/res-keyguard/values-mn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Түгжээг тайлах бол цэсийг дарна уу."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сүлжээ түгжигдсэн"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM карт алга"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Таблетад SIM карт алга."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Утсанд SIM карт алга."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM картыг оруулна уу."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM карт байхгүй, эсвэл унших боломжгүй байна. SIM карт оруулна уу."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Ашиглах боломжгүй SIM карт байна."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4-8 тооноос бүтэх ПИН-г оруулна уу."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK код 8-с цөөнгүй тооноос бүтнэ."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Зөв PUK кодыг дахин оруулна уу. Олон удаагийн оролдлого нь SIM-г хүчингүй болгоно."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ПИН код тохирохгүй байна"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Загварыг хэт олон удаа буруу оруулсан байна"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Та ПИН кодоо <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Та нууц үгээ <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийлээ. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ таблетыг шинэчлэх бөгөөд бүх өгөгдөл нь устах болно."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийлээ.Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ утсыг шинэчлэх бөгөөд бүх өгөгдөл нь устах болно."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийлээ. Энэ таблетыг шинэчлэх бөгөөд ингэснээр бүх өгөгдөл нь устах болно."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийлээ. Энэ утсыг шинэчлэх бөгөөд ингэснээр бүх өгөгдөл нь устах болно."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийсэн байна. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ хэрэглэгчийг устгах бөгөөд ингэснээр хэрэглэгчийн бүх өгөгдөл устах болно."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийсэн байна. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ хэрэглэгчийг устгах бөгөөд ингэснээр хэрэглэгчийн бүх өгөгдөл устах болно."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Та таблетын түгжээг тайлах оролдогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийсэн байна. Ажлын профайлыг устгах бөгөөд ингэснээр профайлын бүх өгөгдөл устах болно."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийлээ. Ажлын профайлыг устгах бөгөөд ингэснээр профайлын бүх өгөгдлийг устгах болно."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Та түгжээ тайлах загварыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд таблетынхаа түгжээг имэйл бүртгэлээрээ тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Та түгжээ тайлах загварыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд утасныхаа түгжээг имэйл бүртгэлээрээ тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM-н ПИН кодыг буруу оруулсан тул та төхөөрөмжийнхөө түгжээг тайлахын тулд оператор компанитайгаа холбогдоно уу."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM-н ПИН код буруу байна. Танд <xliff:g id="NUMBER_1">%d</xliff:g> оролдлого үлдлээ.</item> diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml index 1c9ef544c3cb..9d46fb9c3344 100644 --- a/packages/SystemUI/res-keyguard/values-mr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"अनलॉक करण्यासाठी मेनू दाबा."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लॉक केले"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"सिम कार्ड नाही"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"टॅबलेटमध्ये सिम कार्ड नाही."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"फोनमध्ये सिम कार्ड नाही."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"सिम कार्ड घाला."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"सिम कार्ड गहाळ झाले आहे किंवा ते वाचनीय नाही. सिम कार्ड घाला."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"निरुपयोगी सिम कार्ड."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 ते 8 अंकांचा पिन टाईप करा."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK कोड 8 अंकी किंवा त्यापेक्षा अधिकचा असावा."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"योग्य PUK कोड पुन्हा एंटर करा. पुनःपुन्हा प्रयत्न करणे सिम कायमचे अक्षम करेल."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"पिन कोड जुळत नाहीत"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"खूप जास्त पॅटर्न प्रयत्न"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"तुम्ही तुमचा PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"तुम्ही तुमचा पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने काढला. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हे टॅबलेट रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हे टॅबलेट रीसेट केले जाईल, जे त्याचा सर्व डेटा हटवेल."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, या वापरकर्त्याला काढले जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, या वापरकर्त्याला काढले जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, जे सर्व प्रोफाइल डेटा हटवेल."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, जे सर्व प्रोफाइल डेटा हटवेल."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा टॅब्लेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"सिम पिन कोड चुकीचा आहे तुम्ही आता तुमचे डिव्हाइस अनलॉक करण्यासाठी तुमच्या वाहकाशी संपर्क साधावा."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">चुकीचा सिम पिन कोड, तुमच्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहेत.</item> diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml index d8b63daab6d1..7c8e1b8b9ba5 100644 --- a/packages/SystemUI/res-keyguard/values-ms/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Tekan Menu untuk membuka kunci."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rangkaian dikunci"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Tiada kad SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tiada kad SIM dalam tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Tiada kad SIM dalam telefon."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Masukkan kad SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Kad SIM tiada atau tidak dapat dibaca. Sila masukkan kad SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Kad SIM tidak boleh digunakan."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Taipkan PIN yang mengandungi 4 hingga 8 nombor."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Kod PUK seharusnya 8 nombor atau lebih."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Masukkan semula kod PUK yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kod PIN tidak sepadan"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Terlalu banyak percubaan melukis corak"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Anda telah tersilap taip PIN sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> saat."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Anda telah tersilap taip kata laluan sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> saat."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> saat."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, tablet ini akan ditetapkan semula sekali gus memadamkan semua data."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, telefon ini akan ditetapkan semula sekali gus memadamkan semua data."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Tablet ini akan ditetapkan semula sekali gus memadamkan semua data."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Telefon ini akan ditetapkan semula sekali gus memadamkan semua data."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadamkan semua data pengguna."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadamkan semua data pengguna."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadamkan semua data profil."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadamkan semua data profil."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci tablet anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci telefon anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Kod PIN SIM salah. Anda mesti menghubungi pembawa anda untuk membuka kunci peranti."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Kod PIN SIM salah, tinggal <xliff:g id="NUMBER_1">%d</xliff:g> percubaan.</item> diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml index 83f9b7e57c85..19a5c25a8e8b 100644 --- a/packages/SystemUI/res-keyguard/values-my/strings.xml +++ b/packages/SystemUI/res-keyguard/values-my/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"မီနူးကို နှိပ်၍ လော့ခ်ဖွင့်ပါ။"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"ကွန်ရက်ကို လော့ခ်ချထားသည်"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ဆင်းမ်ကဒ် မရှိပါ"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"တက်ဘလက်ထဲတွင် ဆင်းမ်ကဒ် မရှိပါ။"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ဖုန်းထဲတွင် ဆင်းမ်ကဒ် မရှိပါ။"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ဆင်းမ်ကဒ် ထည့်ပါ။"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ဆင်းမ်ကဒ်မရှိပါ သို့မဟုတ် အသုံးပြု၍မရပါ။ ဆင်းမ်ကဒ်တစ်ခု ထည့်ပါ။"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"အသုံးပြု၍ မရတော့သော ဆင်းမ်ကဒ်။"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"ဂဏန်း ၄ လုံးမှ ၈ လုံးအထိ ရှိသော ပင်နံပါတ်ကို ထည့်ပါ။"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"ပင်နံပါတ် ပြန်ဖွင့်သည့်ကုဒ်သည် ဂဏန်း ၈ လုံးနှင့် အထက် ဖြစ်ရပါမည်။"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"မှန်ကန်သည့် ပင်နံပါတ် ပြန်ဖွင့်သည့်ကုဒ်ကို ပြန်ထည့်ပါ။ ထပ်ခါထပ်ခါမှားယွင်းနေလျှင် ဆင်းမ်ကဒ်ကို အပြီးအပိုင် ပိတ်လိုက်ပါမည်။"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ပင်နံပါတ် ကိုက်ညီမှုမရှိပါ"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ပုံစံထည့်သွင်းရန် ကြိုးစားသည့် အကြိမ်အရေအတွက် အလွန်များနေပါပြီ"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"သင်သည် ပင်နံပါတ်ကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ်မှားယွင်းစွာ ထည့်ခဲ့ပါသည်။ \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"သင်သည် စကားဝှက်ကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ်မှားယွင်းစွာ ထည့်ခဲ့ပါသည်။ \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"သင်သည် ပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ်မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"တက်ဘလက်ကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းခဲ့လျှင် ဤတက်ဘလက်ကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ဖုန်းကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းခဲ့လျှင် ဤဖုန်းကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"တက်ဘလက်ကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ ဤတက်ဘလက်ကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ဖုန်းကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ ဤဖုန်းကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"တက်ဘလက်ကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းခဲ့လျှင် ဤအသုံးပြုသူကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး အသုံးပြုသူဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ဖုန်းကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းသွားလျှင် ဤအသုံးပြုသူကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး အသုံးပြုသူဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"တက်ဘလက်ကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ အလုပ်ပရိုဖိုင်ကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး ပရိုဖိုင်ဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ဖုန်းကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ အလုပ်ပရိုဖိုင်ကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး ပရိုဖိုင်ဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ တက်ဘလက်ကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ ဖုန်းကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ဆင်းမ်ကဒ်ပင်နံပါတ် မှားယွင်းနေသောကြောင့် ယခုအခါ သင့်စက်ပစ္စည်းအား လော့ခ်ဖွင့်ရန် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ရပါမည်။"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">ဆင်းမ်ပင်နံပါတ် မှန်ကန်မှုမရှိပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့်ရှိပါသေးသည်။</item> diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml index e766d59311af..d5aa0e1b2009 100644 --- a/packages/SystemUI/res-keyguard/values-nb/strings.xml +++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Trykk på menyknappen for å låse opp."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Nettverket er låst"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM-kort mangler"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nettbrettet mangler SIM-kort."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonen mangler SIM-kort."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Sett inn et SIM-kort."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-kort mangler eller er uleselig. Sett inn et SIM-kort."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Ubrukelig SIM-kort."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Skriv inn en PIN-kode på fire til åtte sifre."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-koden skal være på åtte eller flere sifre."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Skriv inn den riktige PUK-koden på nytt. Gjentatte forsøk deaktiverer SIM-kortet permanent."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-kodene stemmer ikke overens"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"For mange forsøk på tegning av mønster"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Du har oppgitt feil PIN-kode <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Du har tastet inn passordet ditt feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Du har tegnet opplåsningsmønsteret ditt feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Nettbrettet tilbakestilles etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle dataene på nettbrettet."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Telefonen tilbakestilles etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle dataene på telefonen."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Dette nettbrettet blir tilbakestilt, og alle dataene blir slettet."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Denne telefonen blir tilbakestilt, og alle dataene blir slettet."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Brukeren fjernes etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle brukerdataene."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Brukeren fjernes etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle brukerdataene."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Jobbprofilen blir fjernet, og alle profildataene blir slettet."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Jobbprofilen blir fjernet, og alle profildataene blir slettet."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> feil forsøk blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> feil forsøk blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Feil PIN-kode for SIM-kortet. Du må nå kontakte operatøren din for å låse opp enheten."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Feil PIN-kode for SIM-kortet. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøk igjen.</item> diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml index 4f1ea2a1c512..763dc035ed20 100644 --- a/packages/SystemUI/res-keyguard/values-ne/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"अनलक गर्न मेनु थिच्नुहोस्।"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लक भएको छ"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM कार्ड छैन"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ट्याब्लेटमा SIM कार्ड छैन।"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"फोनमा SIM कार्ड छैन।"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM कार्ड हाल्नुहोस्"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM कार्ड हालिएको छैन वा पढ्न योग्य छैन। SIM कार्ड हाल्नुहोस्।"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM कार्ड काम नलाग्ने भएको छ।"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"४ देखि ८ वटा नम्बर भएको एउटा PIN टाइप गर्नुहोस्।"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK कोड ८ वा सो भन्दा बढी नम्बरको हुनु पर्छ।"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"PUK कोड पुन: प्रविष्टि गर्नुहोस्। पटक-पटकको प्रयासले SIM सदाका लागि असक्षम हुनेछ।"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN कोडहरू मिलेनन्"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"अत्यन्त धेरै ढाँचा कोर्ने प्रयासहरू"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले आफ्नो PIN प्रविष्ट गर्नुभएको छ। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो गलत पासवर्ड प्रविष्ट गर्नुभएको छ। \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले आफ्नो अनलक ढाँचा कोर्नुभएको छ। \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकेन्डमा फेरि कोसिस गर्नुहोस्।"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यो ट्याब्लेट यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यो फोन यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। यो ट्याब्लेट यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। यो फोन यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यस प्रयोगकर्तालाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यस प्रयोगकर्तालाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"तपाईं <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। कार्य प्रोफाइललाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। कार्य प्रोफाइललाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो ट्याब्लेट अनलक गर्न आग्रह गरिनेछ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो फोन अनलक गर्न आग्रह गरिनेछ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM को PIN कोड गलत छ। तपाईंले अब आफ्नो यन्त्र खोल्न आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नै पर्ने हुन्छ।"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM को PIN कोड गलत छ, तपाईं अझै <xliff:g id="NUMBER_1">%d</xliff:g> पटक प्रयास गर्न सक्नुहुन्छ।</item> diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml index 16b3425e08d1..953e32d3a7c7 100644 --- a/packages/SystemUI/res-keyguard/values-nl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Druk op Menu om te ontgrendelen."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netwerk vergrendeld"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Geen simkaart"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Geen simkaart in tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Geen simkaart in telefoon."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Plaats een simkaart."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"De simkaart ontbreekt of kan niet worden gelezen. Plaats een simkaart."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Onbruikbare simkaart."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Geef een pincode van vier tot acht cijfers op."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"De pukcode is minimaal acht cijfers lang."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Geef de juiste pukcode opnieuw op. Bij herhaalde pogingen wordt de simkaart definitief uitgeschakeld."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Pincodes komen niet overeen"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Te veel patroonpogingen"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Je hebt je pincode <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getypt. \n\nProbeer het over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden opnieuw."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Je hebt je wachtwoord <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getypt. \n\nProbeer het over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden opnieuw."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. \n\nProbeer het over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden opnieuw."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze tablet gereset, waardoor alle gegevens worden verwijderd."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze telefoon gereset, waardoor alle gegevens worden verwijderd."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Deze tablet wordt gereset, waardoor alle gegevens worden verwijderd."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Deze telefoon wordt gereset, waardoor alle gegevens worden verwijderd."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Onjuiste pincode voor simkaart. Je moet nu contact opnemen met je provider om je apparaat te ontgrendelen."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Onjuiste pincode voor simkaart. Je hebt nog <xliff:g id="NUMBER_1">%d</xliff:g> pogingen over.</item> diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml index b2e8957e33b0..32738d8c8e27 100644 --- a/packages/SystemUI/res-keyguard/values-or/strings.xml +++ b/packages/SystemUI/res-keyguard/values-or/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ଅନଲକ୍ କରିବା ପାଇଁ ମେନୁକୁ ଦବାନ୍ତୁ।"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"ନେଟୱର୍କକୁ ଲକ୍ କରାଯାଇଛି"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"କୌଣସି SIM କାର୍ଡ ନାହିଁ"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ଟାବଲେଟ୍ରେ କୌଣସି SIM କାର୍ଡ ନାହିଁ।"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ଫୋନରେ କୌଣସି SIM କାର୍ଡ ନାହିଁ।"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ଗୋଟିଏ SIM କାର୍ଡ ଭର୍ତ୍ତି କରନ୍ତୁ।"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM କାର୍ଡ ନାହିଁ କିମ୍ବା ଖରାପ ଅଛି। SIM କାର୍ଡ ଭର୍ତ୍ତି କରନ୍ତୁ।"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM କାର୍ଡଟିକୁ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ।"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 ରୁ 8 ନମ୍ବର ବିଶିଷ୍ଟ ଏକ PIN ଟାଇପ୍ କରନ୍ତୁ।"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK କୋଡ୍ରେ 8ଟି କିମ୍ବା ଅଧିକ ନମ୍ବର ରହିଥାଏ।"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"ଠିକ୍ PUK କୋଡ୍ ପୁଣି ଲେଖନ୍ତୁ। ବାରମ୍ବାର ପ୍ରୟାସ କଲେ SIM କାର୍ଡ ସ୍ଥାୟୀ ରୂପେ ଅକ୍ଷମ ହୋଇଯିବ।"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN କୋଡ୍ ମେଳ ହେଉନାହିଁ"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ଅନେକ ପାଟର୍ନ ପ୍ରୟାସ"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"ଆପଣଙ୍କ PIN ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଟାଇପ୍ କରିଛନ୍ତି। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"ଆପଣଙ୍କ ପାସ୍ୱର୍ଡକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଟାଇପ୍ କରିଛନ୍ତି। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"ଆପଣଙ୍କ ଲକ୍ ଖୋଲିବା ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ଆପଣ ଟାବଲେଟକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଭୁଲ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍ ପ୍ରୟାସ ପରେ, ଏହି ଟାବଲେଟଟି ରିସେଟ୍ ହୋଇଯିବ, ଯାହାଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଲିଟ୍ ହୋଇଯିବ।"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ଆପଣ ଫୋନକୁ ଅନଲକ୍ କରିବାକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଭୁଲ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍ ପ୍ରୟାସ ପରେ, ଏହି ଫୋନଟି ରିସେଟ୍ ହୋଇଯିବ, ଯାହାଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଲିଟ୍ ହୋଇଯିବ।"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ଆପଣ ଟାବଲେଟକୁ ଅନଲକ୍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g> ଥର ଭୁଲ୍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଏହି ଟାବଲେଟକୁ ରିସେଟ୍ କରାଯିବ, ଯାହାଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ଆପଣ ଫୋନଟି ଅନଲକ୍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ୍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଏହି ଫୋନ୍ ରିସେଟ୍ କରାଯିବ, ଯାହା ଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ଆପଣ ଟାବଲେଟ୍ଟିକୁ ଅନଲକ୍ କରିବା ପାଇଁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଚେଷ୍ଟା କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ୍ ପ୍ରୟାସ ପରେ, ୱାର୍କ ପ୍ରୋଫାଇଲ୍କୁ ବାହାର କରିଦିଆଯିବ ଏବଂ ଏହା ଦ୍ୱାରା ସମସ୍ତ ପ୍ରୋଫାଇଲ୍ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ଆପଣ ଫୋନଟି ଅନଲକ୍ କରିବାକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍ ପ୍ରୟାସ ପରେ, ଏହି ୟୁଜରଙ୍କୁ ବାହାର କରିଦିଆଯିବ ଏବଂ ଏହାଦ୍ୱାରା ସମସ୍ତ ୟୁଜର୍ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ଆପଣ ଟାବଲେଟକୁ ଅନଲକ୍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g> ଭୁଲ୍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। କାର୍ଯ୍ୟ ପ୍ରୋଫାଇଲ୍ ବାହାର କରିଦିଆଯିବ, ଯାହାଦ୍ୱାରା ସମସ୍ତ ପ୍ରୋଫାଇଲ୍ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ଆପଣ ଫୋନଟି ଅନଲକ୍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ୍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ୱର୍କ ପ୍ରୋଫାଇଲ୍ ବାହାର କରିଦିଆଯିବ, ଯାହା ଦ୍ୱାରା ସମସ୍ତ ପ୍ରୋଫାଇଲ୍ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ଆପଣଙ୍କ ଅନଲକ୍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଏକ ଇମେଲ୍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ନିଜ ଟାବଲେଟକୁ ଅନଲକ୍ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ଆପଣଙ୍କ ଅନଲକ୍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଏକ ଇମେଲ୍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ନିଜ ଫୋନକୁ ଅନଲକ୍ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ଭୁଲ SIM PIN କୋଡ୍, ଆପଣଙ୍କ ଡିଭାଇସକୁ ଅନଲକ୍ କରିବା ପାଇଁ ଏବେ ହିଁ ନିଜ କେରିଅର୍ଙ୍କ ସହ ସମ୍ପର୍କ କରନ୍ତୁ।"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">ଭୁଲ SIM PIN କୋଡ୍, ଆପଣଙ୍କର ଆଉ <xliff:g id="NUMBER_1">%d</xliff:g>ଟି ପ୍ରୟାସ ବାକି ରହିଛି।</item> diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml index 5e68530ef7dc..c53f42fac31e 100644 --- a/packages/SystemUI/res-keyguard/values-pa/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ਅਣਲਾਕ ਕਰਨ ਲਈ \"ਮੀਨੂ\" ਦਬਾਓ।"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"ਨੈੱਟਵਰਕ ਲਾਕ ਕੀਤਾ ਗਿਆ"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ਕੋਈ ਸਿਮ ਕਾਰਡ ਨਹੀਂ"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ਟੈਬਲੈੱਟ ਵਿੱਚ ਕੋਈ ਸਿਮ ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ।"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ਫ਼ੋਨ ਵਿੱਚ ਕੋਈ ਸਿਮ ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ।"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ਇੱਕ SIM ਕਾਰਡ ਪਾਓ।"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ ਜਾਂ ਪੜ੍ਹਨਯੋਗ ਨਹੀਂ ਹੈ। ਇੱਕ SIM ਕਾਰਡ ਪਾਓ।"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ਨਾ-ਵਰਤਣਯੋਗ SIM ਕਾਰਡ।"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"ਕੋਈ ਪਿੰਨ ਟਾਈਪ ਕਰੋ ਜੋ 4 ਤੋਂ 8 ਨੰਬਰਾਂ ਦਾ ਹੋਵੇ।"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK ਕੋਡ 8 ਜਾਂ ਵੱਧ ਨੰਬਰਾਂ ਦਾ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ।"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"ਸਹੀ PUK ਕੋਡ ਮੁੜ-ਦਾਖਲ ਕਰੋ। ਬਾਰ-ਬਾਰ ਕੀਤੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ ਸਿਮ ਨੂੰ ਸਥਾਈ ਤੌਰ \'ਤੇ ਬੰਦ ਕਰ ਦੇਣਗੀਆਂ।"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ਪਿੰਨ ਕੋਡ ਮੇਲ ਨਹੀਂ ਖਾਂਦੇ"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਪੈਟਰਨ ਕੋਸ਼ਿਸ਼ਾਂ"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"ਤੁਸੀਂ ਆਪਣਾ ਪਿੰਨ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟਾਈਪ ਕੀਤਾ ਹੈ। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਪਾਸਵਰਡ ਗਲਤ ਢੰਗ ਨਾਲ ਟਾਈਪ ਕੀਤਾ ਹੈ।\n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਉਲੀਕਿਆ ਹੈ। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਹ ਟੈਬਲੈੱਟ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਹ ਫ਼ੋਨ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਇਹ ਟੈਬਲੈੱਟ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਇਹ ਫ਼ੋਨ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਵਰਤੋਂਕਾਰ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਵਰਤੋਂਕਾਰ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਉਲੀਕਿਆ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣੇ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਵੇਗਾ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ਗਲਤ ਸਿਮ ਪਿੰਨ ਕੋਡ, ਆਪਣੇ ਡੀਵਾਈਸ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਲਈ ਹੁਣ ਤੁਹਾਨੂੰ ਲਾਜ਼ਮੀ ਤੌਰ \'ਤੇ ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਸੰਪਰਕ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ।"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">ਗਲਤ ਸਿਮ ਪਿੰਨ ਕੋਡ, ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ ਬਾਕੀ ਹੈ।</item> diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml index c9752b9306e1..e3d78780feeb 100644 --- a/packages/SystemUI/res-keyguard/values-pl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Naciśnij Menu, aby odblokować."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sieć zablokowana"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Brak karty SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Brak karty SIM w tablecie."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Brak karty SIM w telefonie."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Włóż kartę SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Brak karty SIM lub nie można jej odczytać. Włóż kartę SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Karta SIM jest zablokowana."</string> @@ -85,17 +83,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Wpisz kod PIN o długości od 4 do 8 cyfr."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Kod PUK musi mieć co najmniej 8 cyfr."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Wpisz poprawny kod PUK. Kolejne próby spowodują trwałe wyłączenie karty SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kody PIN nie pasują"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Zbyt wiele prób narysowania wzoru"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> wpisałeś nieprawidłowy kod PIN. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> wpisałeś nieprawidłowe hasło. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach tablet zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach telefon zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Tablet zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Telefon zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich danych użytkownika."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich danych użytkownika."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -104,10 +95,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Profil służbowy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Profil służbowy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Nieprawidłowy kod PIN karty SIM. Musisz teraz skontaktować się z operatorem, by odblokował Twoje urządzenie."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="few">Nieprawidłowy kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> próby.</item> diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml index 19645c061b72..b74aea9e42b5 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pressione Menu para desbloquear."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Sem chip"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Não há um chip no tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Não há um chip no smartphone."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insira um chip."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"O chip não foi inserido ou não é possível lê-lo. Insira um chip."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Chip inutilizável."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Digite um PIN com 4 a 8 números."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"O código PUK deve ter oito números ou mais."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o chip."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN não coincidem"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Muitas tentativas de padrão"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será redefinido, o que excluirá todos os dados dele."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este smartphone será redefinido, o que excluirá todos os dados dele."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do chip incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Código PIN do chip incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item> diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml index be3ca3e5e8a4..e8600c8c119d 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Prima Menu para desbloquear."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nenhum cartão SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nenhum cartão SIM no tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nenhum cartão SIM no telemóvel."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insira um cartão SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"O cartão SIM está em falta ou não é legível. Insira um cartão SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Cartão SIM inutilizável."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Introduza um PIN com 4 a 8 números."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"O código PUK deve ter 8 ou mais números."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Volte a introduzir o código PUK correto. Demasiadas tentativas consecutivas irão desativar permanentemente o cartão SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN não coincidem"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Demasiadas tentativas para desenhar o padrão"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Introduziu o PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Introduziu a palavra-passe incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Desenhou a sua padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este tablet será reposto, o que eliminará todos os dados do mesmo."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este telemóvel será reposto, o que eliminará todos os dados do mesmo."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será reposto, o que eliminará todos os dados do mesmo."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. Este telemóvel será reposto, o que eliminará todos os dados do mesmo."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados do mesmo."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados do mesmo."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do mesmo."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do mesmo."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do cartão SIM incorreto. Tem de contactar o seu operador para desbloquear o dispositivo."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item> diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml index 19645c061b72..b74aea9e42b5 100644 --- a/packages/SystemUI/res-keyguard/values-pt/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pressione Menu para desbloquear."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Sem chip"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Não há um chip no tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Não há um chip no smartphone."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insira um chip."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"O chip não foi inserido ou não é possível lê-lo. Insira um chip."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Chip inutilizável."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Digite um PIN com 4 a 8 números."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"O código PUK deve ter oito números ou mais."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o chip."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN não coincidem"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Muitas tentativas de padrão"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será redefinido, o que excluirá todos os dados dele."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este smartphone será redefinido, o que excluirá todos os dados dele."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do chip incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Código PIN do chip incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item> diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml index 05d1048b94f5..f8a39f0e8290 100644 --- a/packages/SystemUI/res-keyguard/values-ro/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Apăsați pe Meniu pentru a debloca."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rețea blocată"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Niciun card SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nu există card SIM în tabletă."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nu există card SIM în telefon."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Introduceți un card SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Cardul SIM lipsește sau nu poate fi citit. Introduceți un card SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Card SIM inutilizabil."</string> @@ -84,17 +82,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Introduceți un cod PIN alcătuit din 4 până la 8 cifre."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Codul PUK trebuie să aibă minimum 8 cifre."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Reintroduceți codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Codurile PIN nu coincid"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Prea multe încercări de desenare a modelului"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Ați introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Ați introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, această tabletă va fi resetată, iar toate datele acesteia vor fi șterse."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Această tabletă va fi resetată, iar toate datele acesteia vor fi șterse."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -103,10 +94,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Codul PIN pentru cardul SIM este incorect. Contactați operatorul pentru a vă debloca dispozitivul."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="few">Codul PIN pentru cardul SIM este incorect. V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> încercări.</item> diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml index 53ad97fd9409..4b38fdc9ce66 100644 --- a/packages/SystemUI/res-keyguard/values-ru/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Для разблокировки нажмите \"Меню\"."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сеть заблокирована"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Нет SIM-карты."</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Нет SIM-карты."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Нет SIM-карты."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Вставьте SIM-карту."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-карта отсутствует или недоступна. Вставьте SIM-карту."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM-карта непригодна к использованию."</string> @@ -85,17 +83,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Введите PIN-код (от 4 до 8 цифр)."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-код должен содержать не менее 8 цифр."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Введите правильный PUK-код. После нескольких неудачных попыток SIM-карта будет заблокирована."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коды не совпадают."</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Слишком много попыток ввести графический ключ."</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Вы ввели неверный PIN-код несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>).\n\nПовторите попытку через <xliff:g id="NUMBER_1">%2$d</xliff:g> сек."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Вы ввели неверный пароль несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>).\n\nПовторите попытку через <xliff:g id="NUMBER_1">%2$d</xliff:g> сек."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Вы начертили неверный графический ключ несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>).\n\nПовторите попытку через <xliff:g id="NUMBER_1">%2$d</xliff:g> сек."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Вы пытались разблокировать планшет несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи произойдет сброс настроек и все данные на устройстве будут удалены."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Вы пытались разблокировать телефон несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи произойдет сброс настроек и все данные на устройстве будут удалены."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Достигнуто максимальное количество неудачных попыток разблокировать планшет (<xliff:g id="NUMBER">%d</xliff:g>). Настройки устройства будут сброшены, а все его данные – удалены."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Настройки устройства будут сброшены, а все его данные – удалены."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Вы пытались разблокировать планшет несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи профиль пользователя и все его данные будут удалены."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Вы пытались разблокировать телефон несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи профиль пользователя и все его данные будут удалены."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -104,10 +95,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Достигнуто максимальное количество неудачных попыток разблокировать планшет (<xliff:g id="NUMBER">%d</xliff:g>). Рабочий профиль и все его данные будут удалены."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Рабочий профиль и все его данные будут удалены."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Вы ввели неверный графический ключ несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать планшет с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Вы ввели неверный графический ключ несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать телефон с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Неверный PIN-код. Обратитесь к оператору связи, чтобы разблокировать SIM-карту."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Неверный PIN-код. Осталась <xliff:g id="NUMBER_1">%d</xliff:g> попытка.</item> diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml index fe1b7e90a56d..d64601810d49 100644 --- a/packages/SystemUI/res-keyguard/values-si/strings.xml +++ b/packages/SystemUI/res-keyguard/values-si/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"අගුලු හැරීමට මෙනුව ඔබන්න."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"ජාලය අගුළු දමා ඇත"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM පත නැත"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ටැබ්ලටයේ SIM පත නොමැත."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"දුරකථනය තුල SIM පතක් නැත."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM කාඩ්පතක් ඇතුළු කරන්න."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM පත නොමැත හෝ කියවිය නොහැක. SIM පතක් ඇතුලත් කරන්න."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"භාවිතා කළ නොහැකි SIM පත."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 සිට 8 දක්වා අංක සහිත PIN එකක් ටයිප් කරන්න."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK කේතය සංඛ්යා 8 ක් හෝ වැඩි විය යුතුය."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"නිවැරදි PUK කේතය නැවත ඇතුලත් කරන්න. නැවත නැවත උත්සාහ කිරීමෙන් SIM එක ස්ථිරවම අබල කරයි."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN කේත නොගැළපේ."</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"රටා උත්සාහ කිරීම් වැඩිය"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"ඔබ PIN අංකය <xliff:g id="NUMBER_0">%1$d</xliff:g> වාරයක් වැරදියට ටයිප් කොට ඇත.\n\n තත්පර <xliff:g id="NUMBER_1">%2$d</xliff:g> ක් ඇතුළත නැවත උත්සාහ කරන්න."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"ඔබ මුරපදය වාර <xliff:g id="NUMBER_0">%1$d</xliff:g> ක් වැරදියට ටයිප්කොට ඇත. \n\nතත්පර <xliff:g id="NUMBER_1">%2$d</xliff:g> කින් නැවත උත්සහ කරන්න."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"ඔබ <xliff:g id="NUMBER_0">%1$d</xliff:g> වාරයක් අගුළු ඇරීමේ රටාව වැරදියට ඇඳ ඇත. \n\nතත්පර <xliff:g id="NUMBER_1">%2$d</xliff:g> ක් ඇතුළත නැවත උත්සාහ කරන්න."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම ටැබ්ලට් පරිගණකය යළි සකසනු ඇති අතර, එය එහි සියලු දත්ත මකනු ඇත."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම දුරකථනය යළි සකසනු ඇති අතර, එය එහි සියලු දත්ත මකනු ඇත."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. මෙම ටැබ්ලට් පරිගණකය යළි සකසනු ඇති අතර, එය එහි සියලු පදත්ත මකනු ඇත."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. මෙම දුරකථනය යළි සකසනු ඇති අතර, එය එහි සියලු පදත්ත මකනු ඇත."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම පරිශීලකයා ඉවත් කරනු ඇති අතර, එය සියලු පරිශීලක දත්ත මකනු ඇත."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම පරිශීලකයා ඉවත් කරනු ඇති අතර, එය සියලු පරිශීලක දත්ත මකනු ඇත."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. කාර්යාල පැතිකඩ ඉවත් කරනු ඇති අතර, එය සියලු පැතිකඩ දත්ත මකනු ඇත."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. කාර්යාල පැතිකඩ ඉවත් කරනු ඇති අතර, එය සියලු පැතිකඩ දත්ත මකනු ඇත."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ඔබ අගුළු ඇරිමේ රටාව <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් වැරදියට ඇඳ ඇත. තවත් අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%2$d</xliff:g> කින් පසුව, ඊ-තැපැල් ගිණුම භාවිතා කරමින් ඔබගේ ටැබ්ලටයේ අගුළු ඇරීමට ඔබට පවසනු ඇත.\n\n නැවත තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> කින් උත්සාහ කරන්න."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%2$d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"වැරදී SIM PIN කේතයකි, ඔබගේ දුරකතනයේ අඟුල හැරීමට ඔබගේ වාහකයා ඔබ දැන් සම්බන්ධ කරගත යුතුය."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">වැරදී SIM PIN කේතයකි, ඔබගේ දුරකථනයේ අඟුල හැරීමට ඔබගේ වාහකයා සම්බන්ධ කරගැනීමට පෙර ඔබ සතුව තවත් උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත.</item> diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml index 27b0e8ef0fbd..7be6ed20e935 100644 --- a/packages/SystemUI/res-keyguard/values-sk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Odomknete stlačením tlačidla ponuky."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sieť je zablokovaná"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Žiadna SIM karta"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"V tablete nie je žiadna SIM karta."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"V telefóne nie je žiadna SIM karta."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Vložte SIM kartu."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM karta chýba alebo sa z nej nedá čítať. Vložte SIM kartu."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM karta je nepoužiteľná."</string> @@ -85,17 +83,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Zadajte kód PIN s dĺžkou 4 až 8 číslic."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Kód PUK musí obsahovať 8 alebo viac číslic."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Znova zadajte správny kód PUK. Opakované pokusy zakážu SIM kartu natrvalo."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kódy PIN sa nezhodujú"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Príliš veľa pokusov o nakreslenie vzoru"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Už <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste zadali nesprávny kód PIN. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Už <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste zadali nesprávne heslo. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Už <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste použili nesprávny bezpečnostný vzor. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento tablet obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento telefón obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tablet ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Tablet bude obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Telefón bude obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento používateľ odstránený a spolu s ním všetky jeho údaje."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento používateľ odstránený a spolu s ním všetky jeho údaje."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -104,10 +95,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tablet ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Už ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%2$d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Už ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g>} s."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Nesprávny kód PIN SIM karty. Teraz musíte kontaktovať svojho operátora, aby vám odomkol zariadenie."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="few">Nesprávny kód PIN SIM karty. Zostávajú vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusy.</item> diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml index 8f08b0bcd5dc..6286d10ae40c 100644 --- a/packages/SystemUI/res-keyguard/values-sl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Če želite odkleniti, pritisnite meni."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Omrežje je zaklenjeno"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Ni kartice SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"V tabličnem računalniku ni kartice SIM."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"V telefonu ni kartice SIM."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Vstavite kartico SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Ni kartice SIM ali je ni mogoče prebrati. Vstavite kartico SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Neuporabna kartica SIM."</string> @@ -85,17 +83,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Vnesite kodo PIN, ki vsebuje od štiri do osem številk."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Koda PUK mora biti 8- ali večmestno število."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Znova vnesite pravilno kodo PUK. Večkratni poskusi bodo trajno onemogočili kartico SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kodi PIN se ne ujemata"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Preveč poskusov vnosa vzorca"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Kodo PIN ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat vnesli napačno. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Geslo ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat vnesli napačno. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat nepravilno narisali. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ponastavljen in vsi podatki v njem bodo izbrisani."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ponastavljen in vsi podatki v njem bodo izbrisani."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat, zato bo ponastavljen, vsi podatki v njem pa bodo izbrisani."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat, zato bo ponastavljen, vsi podatki v njem pa bodo izbrisani."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ta uporabnik odstranjen in vsi podatki uporabnika bodo izbrisani."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ta uporabnik odstranjen in vsi podatki uporabnika bodo izbrisani."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -104,10 +95,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen in vsi podatki profila bodo izbrisani."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen in vsi podatki profila bodo izbrisani."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\n Poskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da telefon odklenete z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Napačna koda PIN kartice SIM. Zdaj se boste morali za odklenitev naprave obrniti na operaterja."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Napačna koda PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskus.</item> diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml index 13361885ff9c..3980b0eb98dc 100644 --- a/packages/SystemUI/res-keyguard/values-sq/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Shtyp \"Meny\" për të shkyçur."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rrjeti është i kyçur"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nuk ka kartë SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nuk ka kartë SIM në tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Në telefon nuk ka kartë SIM."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Fut një kartë SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Karta SIM mungon ose është e palexueshme. Fut një kartë të re SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Kartë SIM është e papërdorshme."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Shkruaj një PIN me 4 deri në 8 numra."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Kodi PUK duhet të jetë me 8 numra ose më shumë."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Fut kodin e saktë PUK. Provat e përsëritura do ta çaktivizojnë përgjithmonë kartën SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kodet PIN nuk përputhen"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Shumë tentativa për motivin"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"E ke shkruar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht kodin PIN.\n\nProvo sërish për <xliff:g id="NUMBER_1">%2$d</xliff:g> sekonda."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"E ke shkruar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht fjalëkalimin.\n\nProvo sërish për <xliff:g id="NUMBER_1">%2$d</xliff:g> sekonda."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për të vizatuar motivin tënd. \n\nProvo sërish për <xliff:g id="NUMBER_1">%2$d</xliff:g> sekonda."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht për ta shkyçur tabletin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> përpjekjeve të tjera të pasuksesshme, tableti do të rivendoset, gjë që do të rivendosë të gjitha të dhënat e tij."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> përpjekjeve të tjera të pasuksesshme, telefoni do të rivendoset, gjë që do të fshijë të gjitha të dhënat e tij."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Ky tablet do të rivendoset, gjë që do të fshijë të gjitha të dhënat e tij."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Ky telefon do të rivendoset, gjë që do të fshijë të gjitha të dhënat e tij."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, përdoruesi do të hiqet dhe të gjitha të dhënat e përdoruesit në të, do të fshihen."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, përdoruesi do të hiqet dhe të gjitha të dhënat e përdoruesit në të, do të fshihen."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Profili i punës do të hiqet, gjë që do të fshijë të gjitha të dhënat e profilit."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Profili i punës do të hiqet, gjë që do të fshijë të gjitha të dhënat e profilit."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd të shkyçjes. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh tabletin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd të shkyçjes. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh telefonin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Kodi PIN i kartës SIM është i pasaktë. Tani duhet të kontaktosh me operatorin për ta shkyçur pajisjen tënde."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Kodi PIN i kartës SIM është i pasaktë. Të kanë mbetur edhe <xliff:g id="NUMBER_1">%d</xliff:g> tentativa.</item> diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml index 41869e96962c..9d5ed2831dba 100644 --- a/packages/SystemUI/res-keyguard/values-sr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Притисните Мени да бисте откључали."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежа је закључана"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Нема SIM картице"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"У таблету нема SIM картице."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"У телефону нема SIM картице."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Уметните SIM картицу."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM картица недостаје или не може да се прочита. Уметните SIM картицу."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM картица је неупотребљива."</string> @@ -84,17 +82,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Унесите PIN који има 4–8 бројева."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK кôд треба да има 8 или више бројева."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Поново унесите тачан PUK кôд. Поновљени покушаји ће трајно онемогућити SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN кодови се не подударају"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Превише покушаја уноса шаблона"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Унели сте погрешан PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> сек."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Унели сте погрешну лозинку <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> сек."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Нацртали сте нетачан шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> сек."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, овај таблет ће се ресетовати, чиме се бришу сви подаци корисника."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, овај телефон ће се ресетовати, чиме се бришу сви подаци корисника."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Овај таблет ће се ресетовати, чиме се бришу сви подаци."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Овај телефон ће се ресетовати, чиме се бришу сви подаци."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо овог корисника, чиме се бришу сви подаци корисника."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо овог корисника, чиме се бришу сви подаци корисника."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -103,10 +94,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо профил за Work, чиме се бришу сви подаци са профила."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо профил за Work, чиме се бришу сви подаци са профила."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате таблет помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате телефон помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Нетачан PIN кôд за SIM. Сада морате да контактирате мобилног оператера да бисте откључали уређај."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Нетачан PIN кôд за SIM. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај.</item> diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml index c35fc1a9ca50..595f4118e3e6 100644 --- a/packages/SystemUI/res-keyguard/values-sv/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Lås upp genom att trycka på Meny."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Nätverk låst"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Inget SIM-kort"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Inget SIM-kort i surfplattan."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Inget SIM-kort i mobilen."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Sätt i ett SIM-kort."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-kort saknas eller kan inte läsas. Sätt i ett SIM-kort."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Oanvändbart SIM-kort."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Ange en pinkod med fyra till åtta siffror."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-koden ska vara minst åtta siffror."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Ange rätt PUK-kod. Om försöken upprepas inaktiveras SIM-kortet permanent."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Pinkoderna stämmer inte överens"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"För många försök med grafiskt lösenord"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Du har angett fel pinkod <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök återställs surfplattan och all data raderas."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök återställs mobilen och all data raderas."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Surfplattan återställs och all data raderas."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Mobilen återställs och all data raderas."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök tas användaren bort och all användardata raderas."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök tas användaren bort och all användardata raderas."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp surfplattan med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Du angav fel pinkod för SIM-kortet och måste nu kontakta operatören för att låsa upp enheten."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Du angav fel pinkod för SIM-kortet. <xliff:g id="NUMBER_1">%d</xliff:g> försök återstår.</item> diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml index 30749bd9957e..cb6409e2eed1 100644 --- a/packages/SystemUI/res-keyguard/values-sw/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Bonyeza Menyu ili kufungua."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mtandao umefungwa"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Hakuna SIM kadi"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Hakuna SIM kadi katika kompyuta kibao."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Hakuna SIM kadi kwenye simu."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Weka SIM kadi."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM kadi haiko au haisomeki. Weka SIM kadi."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM kadi isiyotumika."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Andika PIN ya tarakimu 4 hadi 8."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Nambari ya PUK inafaa kuwa na tarakimu 8 au zaidi."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Weka tena nambari sahihi wa PUK. Ukirudia mara nyingi utafunga SIM kabisa."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Nambari za PIN hazifanani"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Umejaribu kuchora mchoro mara nyingi mno"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Umeandika vibaya PIN mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Umeandika vibaya nenosiri lako mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Umechora vibaya mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Umejaribu kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, kompyuta hii kibao itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Umejaribu kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, simu hii itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Kompyuta hii kibao itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Simu hii itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Umejaribu kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, mtumiaji huyu ataondolewa, hatua itakayofuta data yake yote."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Umejaribu kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, mtumiaji huyu ataondolewa, hatua itakayofuta data yake yote."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Umejaribu kufungua kompyuta kibao mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa kufungua kompyuta yako kibao kwa kutumia akaunti yako ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Nambari ya PIN ya SIM si sahihi, sasa lazima uwasiliane na mtoa huduma za mtandao ndipo ufungue kifaa chako."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Nambari ya PIN ya SIM si sahihi. Una nafasi zingine <xliff:g id="NUMBER_1">%d</xliff:g> za kujaribu.</item> diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml index 756bd8c92041..63e1a1e78eec 100644 --- a/packages/SystemUI/res-keyguard/values-ta/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"திறக்க, மெனுவை அழுத்தவும்."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"நெட்வொர்க் பூட்டப்பட்டது"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"சிம் கார்டு இல்லை"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"டேப்லெட்டில் சிம் கார்டு இல்லை."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"மொபைலில் சிம் கார்டு இல்லை."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"சிம் கார்டைச் செருகவும்."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"சிம் கார்டு செருகப்படவில்லை அல்லது படிக்கக்கூடியதாக இல்லை. சிம் கார்டைச் செருகவும்."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"பயன்படுத்த முடியாத சிம் கார்டு."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 இலிருந்து 8 எண்கள் உள்ள பின்னை உள்ளிடவும்."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK குறியீட்டில் 8 அல்லது அதற்கும் அதிகமான எண்கள் இருக்க வேண்டும்."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"சரியான PUK குறியீட்டை மீண்டும் உள்ளிடவும். தொடர் முயற்சிகள் சிம்மை நிரந்தரமாக முடக்கிவிடும்."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"பின் குறியீடுகள் பொருந்தவில்லை"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"பேட்டர்னை அதிக முறை தவறாக வரைந்துவிட்டீர்கள்"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"உங்கள் பின்னை <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக உள்ளிட்டுவிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"உங்கள் கடவுச்சொல்லை <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக உள்ளிட்டுவிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"திறப்பதற்கான பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்த டேப்லெட் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"மொபைலைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்த மொபைல் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இந்த டேப்லெட் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இந்த மொபைல் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்தப் பயனர் அகற்றப்பட்டு, எல்லாப் பயனர் தரவும் நீக்கப்படும்."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"மொபைலைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்தப் பயனர் அகற்றப்பட்டு, எல்லாப் பயனர் தரவும் நீக்கப்படும்."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். பணிக் கணக்கு அகற்றப்பட்டு, எல்லாச் சுயவிவரத் தரவும் நீக்கப்படும்."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். பணிக் கணக்கு அகற்றப்பட்டு, எல்லாச் சுயவிவரத் தரவும் நீக்கப்படும்."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"திறப்பதற்கான பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி டேப்லெட்டைத் திறக்கும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"திறப்பதற்கான பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி மொபைலைத் திறக்கும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"சிம்மின் பின் குறியீடு தவறானது. இனி சாதனத்தைத் திறக்க, உங்கள் தொலைத்தொடர்பு நிறுவனத்தைத் தொடர்புகொள்ள வேண்டும்."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">சிம்மின் பின் குறியீடு தவறானது, இன்னும் நீங்கள் <xliff:g id="NUMBER_1">%d</xliff:g> முறை முயலலாம்.</item> diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml index f9986d9b9487..a2f45c9740b1 100644 --- a/packages/SystemUI/res-keyguard/values-te/strings.xml +++ b/packages/SystemUI/res-keyguard/values-te/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"అన్లాక్ చేయడానికి మెనుని నొక్కండి."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"నెట్వర్క్ లాక్ చేయబడింది"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM కార్డ్ లేదు"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"టాబ్లెట్లో SIM కార్డ్ లేదు."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ఫోన్లో SIM కార్డ్ లేదు."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM కార్డ్ని చొప్పించండి."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM కార్డ్ లేదు లేదా ఆమోదయోగ్యం కాదు. SIM కార్డ్ని చొప్పించండి."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM కార్డ్ నిరుపయోగకరంగా మారింది."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 నుండి 8 సంఖ్యలు ఉండే పిన్ను టైప్ చేయండి."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK కోడ్ అనేది 8 లేదా అంతకంటే ఎక్కువ సంఖ్యలు ఉండాలి."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"సరైన PUK కోడ్ను మళ్లీ నమోదు చేయండి. ఎక్కువసార్లు ప్రయత్నించడం వలన SIM శాశ్వతంగా నిలిపివేయబడుతుంది."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"పిన్ కోడ్లు సరిపోలలేదు"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"నమూనాని చాలా ఎక్కువసార్లు గీసారు"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"మీరు మీ పిన్ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"మీరు మీ పాస్వర్డ్ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ టాబ్లెట్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ ఫోన్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. ఈ టాబ్లెట్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. ఈ ఫోన్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ వినియోగదారు తీసివేయబడతారు, తద్వారా వినియోగదారు డేటా మొత్తం తొలగించబడుతుంది."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"మీరు ఫోన్ని అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ వినియోగదారు తీసివేయబడతారు, తద్వారా వినియోగదారు డేటా మొత్తం తొలగించబడుతుంది."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, తద్వారా ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"మీరు ఫోన్ని అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, తద్వారా ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీరు ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్ను అన్లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీరు ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్ను అన్లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM పిన్ కోడ్ తప్పు, ఇప్పుడు మీ డివైజ్ను అన్లాక్ చేయాలంటే, మీరు తప్పనిసరిగా మీ క్యారియర్ను సంప్రదించాలి."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM పిన్ కోడ్ తప్పు, మీకు మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి.</item> diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml index 62b04dcfdda4..ce40efb8a808 100644 --- a/packages/SystemUI/res-keyguard/values-th/strings.xml +++ b/packages/SystemUI/res-keyguard/values-th/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"กด \"เมนู\" เพื่อปลดล็อก"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"เครือข่ายถูกล็อก"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ไม่มีซิมการ์ด"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ไม่มีซิมการ์ดในแท็บเล็ต"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ไม่มีซิมการ์ดในโทรศัพท์"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ใส่ซิมการ์ด"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ไม่มีซิมการ์ดหรือไม่สามารถอ่านได้ โปรดใส่ซิมการ์ด"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ซิมการ์ดใช้ไม่ได้"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"พิมพ์ PIN ซึ่งเป็นเลข 4-8 หลัก"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"รหัส PUK ต้องเป็นตัวเลขอย่างน้อย 8 หลัก"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"ใส่รหัส PUK ที่ถูกต้องอีกครั้ง การพยายามซ้ำหลายครั้งจะทำให้ซิมการ์ดถูกปิดใช้งานอย่างถาวร"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"รหัส PIN ไม่ตรง"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ลองหลายรูปแบบมากเกินไป"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"คุณพิมพ์ PIN ไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%2$d</xliff:g> วินาที"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"คุณพิมพ์รหัสผ่านไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%2$d</xliff:g> วินาที"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> วินาที"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะรีเซ็ตแท็บเล็ตเครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะรีเซ็ตโทรศัพท์เครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตแท็บเล็ตเครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตโทรศัพท์เครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลทั้งหมดของผู้ใช้"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลทั้งหมดของผู้ใช้"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"รหัส PIN ของซิมไม่ถูกต้อง ตอนนี้คุณต้องติดต่อผู้ให้บริการเพื่อปลดล็อกอุปกรณ์ของคุณ"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">รหัส PIN ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง</item> diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml index 4841eaee1372..15f9616b0d85 100644 --- a/packages/SystemUI/res-keyguard/values-tl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pindutin ang Menu upang i-unlock."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Naka-lock ang network"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Walang SIM card"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Walang SIM card sa tablet."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Walang SIM card sa telepono."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Maglagay ng SIM card."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Wala o hindi nababasa ang SIM card. Maglagay ng SIM card."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Hindi na magagamit na SIM card."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Mag-type ng PIN na 4 hanggang 8 numero."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Dapat ay 8 numero o higit pa ang PUK code."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Muling ilagay ang tamang PUK code. Permanenteng madi-disable ang SIM dahil sa paulit-ulit na pagsubok."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Hindi nagtutugma ang mga PIN code"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Masyadong maraming pagsubok sa pattern"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Na-type mo nang mali ang iyong PIN nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%2$d</xliff:g> (na) segundo."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Na-type mo nang hindi tama ang iyong password nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%2$d</xliff:g> (na) segundo."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%2$d</xliff:g> (na) segundo."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, ire-reset ang tablet na ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, ire-reset ang teleponong ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Ire-reset ang tablet na ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Ire-reset ang teleponong ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Mali ang PIN code ng SIM, dapat ka nang makipag-ugnayan sa iyong carrier upang i-unlock ang iyong device."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Mali ang PIN code ng SIM, mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> natitirang pagsubok.</item> diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml index 398516352b0a..2ddf26eaf83a 100644 --- a/packages/SystemUI/res-keyguard/values-tr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Kilidi açmak için Menü\'ye basın."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Ağ kilitli"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM kart yok"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tablette SIM kart yok."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonda SIM kart yok."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM kart takın."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM kart yok veya okunamıyor. Bir SIM kart takın."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Kullanılamayan SIM kartı"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 ila 8 haneli bir PIN yazın."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kodu 8 veya daha çok basamaklı bir sayı olmalıdır."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Doğru PUK kodunu tekrar girin. Çok sayıda deneme yapılırsa SIM kart kalıcı olarak devre dışı bırakılır."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodları eşleşmiyor"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Çok fazla sayıda desen denemesi yapıldı"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN kodunuzu <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış girdiniz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniye içinde tekrar deneyin."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Şifrenizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış yazdınız. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniye içinde tekrar deneyin."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniye içinde tekrar deneyin."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tabletin kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu tablet sıfırlanacak ve tüm verileri silinecektir."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefonun kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu telefon sıfırlanacak ve tüm verileri silinecektir."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tabletin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu tablet sıfırlanacak ve tüm verileri silinecektir."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu telefon sıfırlanacak ve tüm verileri silinecektir."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tabletin kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefonun kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tabletin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> defa yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız denemeden sonra, tabletinizin kilidini bir e-posta hesabı kullanarak açmanız istenir.\n<xliff:g id="NUMBER_2">%3$d</xliff:g>\n saniye içinde tekrar deneyin."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız denemeden sonra telefonunuzun kilidini bir e-posta hesabı kullanarak açmanız istenir.\n<xliff:g id="NUMBER_2">%3$d</xliff:g>\n saniye içinde tekrar deneyin."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Yanlış SIM PIN kodu. Cihazınızın kilidini açmak için artık operatörünüzle bağlantı kurmanız gerekiyor."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Yanlış SIM PIN kodu, <xliff:g id="NUMBER_1">%d</xliff:g> deneme hakkınız kaldı.</item> diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml index 097d7351b244..fd157454dd1a 100644 --- a/packages/SystemUI/res-keyguard/values-uk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Натисніть меню, щоб розблокувати."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мережу заблоковано"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Немає SIM-карти"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"У пристрої немає SIM-карти."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"У телефоні немає SIM-карти."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Вставте SIM-карту."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-карта відсутня або недоступна для читання. Вставте SIM-карту."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Непридатна SIM-карта."</string> @@ -85,17 +83,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Введіть PIN-код із 4–8 цифр."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-код має складатися зі щонайменше 8 цифр."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Повторно введіть правильний PUK-код. Численні спроби назавжди вимкнуть SIM-карту."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коди не збігаються"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Забагато спроб намалювати ключ"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN-код неправильно введено стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Пароль неправильно введено стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде скинуто налаштування планшета й видалено всі його дані."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде скинуто налаштування телефона й видалено всі його дані."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER">%d</xliff:g>. Буде скинуто налаштування цього планшета й видалено всі його дані."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде скинуто налаштування цього телефона й видалено всі його дані."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде видалено цього користувача й усі його дані."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде видалено цього користувача й усі його дані."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -104,10 +95,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з’явиться запит розблокувати планшет за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Неправильний PIN-код SIM-карти. Зв’яжіться зі своїм оператором, щоб розблокувати пристрій."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Неправильний PIN-код SIM-карти. У вас залишилася <xliff:g id="NUMBER_1">%d</xliff:g> спроба.</item> diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml index 0a4340f2d33a..04d29c60d5f3 100644 --- a/packages/SystemUI/res-keyguard/values-ur/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"غیر مقفل کرنے کیلئے مینو دبائیں۔"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"نیٹ ورک مقفل ہو گیا"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"کوئی SIM کارڈ نہیں ہے"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ٹیبلیٹ میں کوئی SIM کارڈ نہیں ہے۔"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"فون میں کوئی SIM کارڈ نہيں ہے۔"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ایک SIM کارڈ داخل کریں۔"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM کارڈ غائب ہے یا پڑھنے کے قابل نہیں ہے۔ ایک SIM کارڈ داخل کریں۔"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ناقابل استعمال SIM کارڈ۔"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"ایسا PIN ٹائپ کریں جو 4 تا 8 اعداد پر مشتمل ہو۔"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK کوڈ 8 یا زائد اعداد پر مشتمل ہونا چاہیے۔"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"صحیح PUK کوڈ دوبارہ درج کریں۔ بار بار کی کوششیں SIM کو مستقل طور پر غیر فعال کر دیں گی۔"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN کوڈز مماثل نہیں ہیں"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"پیٹرن کی بہت ساری کوششیں"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"آپ نے اپنا PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"آپ نے اپنا پاسورڈ <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس ٹیبلیٹ کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس فون کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ اس ٹیبلیٹ کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ اس فون کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا ٹیبلیٹ غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"غلط SIM PIN کوڈ، اب آپ کو اپنا آلہ غیر مقفل کرنے کیلئے اپنے کیریئر سے رابطہ کرنا ہوگا۔"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">غلط SIM PIN کوڈ، آپ کے پاس <xliff:g id="NUMBER_1">%d</xliff:g> کوششیں بچی ہیں۔</item> diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml index 1780ba010c72..ce461febc775 100644 --- a/packages/SystemUI/res-keyguard/values-uz/strings.xml +++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Qulfdan chiqarish uchun Menyu tugmasini bosing."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Tarmoq qulflangan"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM karta solinmagan"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planshetingizda SIM karta yo‘q."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefoningizda SIM karta yo‘q."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Telefonga SIM karta soling."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM karta solinmagan yoki u yaroqsiz. SIM karta soling."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Foydalanib bo‘lmaydigan SIM karta."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4-8 ta raqamdan iborat PIN kodni kiriting."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kod kamida 8 ta raqamdan iborat bo‘lishi shart."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"To‘g‘ri PUK kodni qayta kiriting. Qayta-qayta urinishlar SIM kartani butunlay o‘chirib qo‘yadi."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kod mos kelmadi"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Grafik kalit juda ko‘p marta chizildi"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN kod <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato kiritildi. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan keyin qaytadan urining."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Parol <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato kiritildi. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan keyin qaytadan urining."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato kiritildi. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan keyin qayta urining."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu planshetda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu telefonda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu planshetda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu telefonda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ishchi profil o‘chirib tashlanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ishchi profil o‘chirib tashlanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin, sizdan e-pochtangizdan foydalanib, planshet qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin yana urinib ko‘ring."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin qayta urinib ko‘ring."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM kartaning PIN kodi xato. Qurilma qulfini ochish uchun operatoringizga murojaat qiling."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM kartaning PIN kodi noto‘g‘ri. Sizda yana <xliff:g id="NUMBER_1">%d</xliff:g> ta urinish qoldi.</item> diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml index 57b359a82c70..3ac2cd263461 100644 --- a/packages/SystemUI/res-keyguard/values-vi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Nhấn vào Menu để mở khóa."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mạng đã bị khóa"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Không có thẻ SIM"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Không có thẻ SIM nào trong máy tính bảng."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Không có thẻ SIM nào trong điện thoại."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Lắp thẻ SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Thẻ SIM bị thiếu hoặc không thể đọc được. Hãy lắp thẻ SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Thẻ SIM không sử dụng được."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Nhập mã PIN có từ 4 đến 8 số."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Mã PUK phải có từ 8 số trở lên."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Hãy nhập lại mã PUK chính xác. Nhiều lần lặp lại sẽ vô hiệu hóa vĩnh viễn thẻ SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Mã PIN không khớp"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Quá nhiều lần nhập hình mở khóa"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Bạn đã nhập sai mã PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%2$d</xliff:g> giây."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Bạn đã nhập sai mật khẩu <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%2$d</xliff:g> giây."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%2$d</xliff:g> giây."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, máy tính bảng này sẽ được đặt lại, tức là tất cả dữ liệu của máy tính bảng sẽ bị xóa."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, điện thoại này sẽ được đặt lại, tức là tất cả dữ liệu của điện thoại sẽ bị xóa."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER">%d</xliff:g> lần. Máy tính bảng này sẽ được đặt lại, tức là tất cả dữ liệu của máy tính bảng sẽ bị xóa."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Điện thoại này sẽ được đặt lại, tức là tất cả dữ liệu của điện thoại sẽ bị xóa."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Mã PIN của SIM không chính xác, bây giờ bạn phải liên hệ với nhà cung cấp dịch vụ để mở khóa thiết bị của mình."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">Mã PIN của SIM không chính xác, bạn còn <xliff:g id="NUMBER_1">%d</xliff:g> lần thử.</item> diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml index 54f1296d75e3..0d979466d1b8 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"按“菜单”即可解锁。"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"网络已锁定"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"没有 SIM 卡"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"平板电脑中没有 SIM 卡。"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"手机中没有 SIM 卡。"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"请插入 SIM 卡。"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM 卡缺失或无法读取,请插入 SIM 卡。"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM 卡无法使用。"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"请输入 4 到 8 位数的 PIN 码。"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK 码应至少包含 8 位数字。"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"请重新输入正确的 PUK 码。如果屡次输入错误,SIM 卡将被永久停用。"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 码不匹配"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"图案尝试次数过多"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"您已经 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次输错 PIN 码。\n\n请在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒后重试。"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"您已经 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次输错密码。\n\n请在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒后重试。"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"您已经 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。\n\n请在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒后重试。"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,平板电脑将会被重置,而这将删除其中的所有数据。"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,手机将会被重置,而这将删除其中的所有数据。"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。这部平板电脑将会被重置,而这将删除其中的所有数据。"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。这部手机将会被重置,而这将删除其中的所有数据。"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统将移除此用户,而这将删除所有的用户数据。"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统将移除此用户,而这将删除所有的用户数据。"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM 卡 PIN 码不正确,您现在必须联系运营商为您解锁设备。"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM 卡 PIN 码不正确,您还有 <xliff:g id="NUMBER_1">%d</xliff:g> 次尝试机会。</item> diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml index c49380ecfbe9..1f55b32dfa0d 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"按下 [選單] 即可解鎖。"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"網絡已鎖定"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"沒有 SIM 卡"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"平板電腦中沒有 SIM 卡。"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"手機中沒有 SIM 卡。"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"請插入 SIM 卡。"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"找不到或無法讀取 SIM 卡。請插入 SIM 卡。"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM 卡無法使用。"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"請輸入 4 至 8 位數的 PIN 碼。"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK 碼應由 8 個或以上數字組成。"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"請重新輸入正確的 PUK 碼。如果錯誤輸入的次數過多,SIM 卡將永久停用。"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 碼不符"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"上鎖圖案畫錯次數過多"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"您已輸入錯誤的 PIN 碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"您已輸入錯誤的密碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將重設此平板電腦,而平板電腦的所有資料亦會一併刪除。"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將重設此手機,而手機的所有資料亦會一併刪除。"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將重設此平板電腦,而平板電腦的所有資料亦會一併刪除。"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將重設此手機,而手機的所有資料亦會一併刪除。"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將移除此使用者,而所有使用者資料亦會一併刪除。"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將移除此使用者,而所有使用者資料亦會一併刪除。"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM 卡 PIN 碼不正確,您現在必須聯絡流動網絡供應商為您的裝置解鎖。"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM 卡的 PIN 碼不正確,您還有 <xliff:g id="NUMBER_1">%d</xliff:g> 次輸入機會。</item> diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml index 4d4d3604d18d..97653c9e4d89 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"按選單鍵解鎖。"</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"網路已鎖定"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"沒有 SIM 卡"</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"平板電腦中沒有 SIM 卡。"</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"手機中沒有 SIM 卡。"</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"請插入 SIM 卡。"</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"找不到或無法讀取 SIM 卡。請插入 SIM 卡。"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM 卡無法使用。"</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"請輸入 4 到 8 碼的 PIN 碼。"</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK 碼至少必須為 8 碼。"</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"請重新輸入正確的 PUK 碼。如果錯誤次數過多,SIM 卡將會遭到永久停用。"</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 碼不符"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"解鎖圖案畫錯次數過多"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"你已輸入錯誤的 PIN 碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"你已輸入錯誤的密碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"你已畫出錯誤的解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會重設這台平板電腦,其中的所有資料也會一併遭到刪除。"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會重設這支手機,其中的所有資料也會一併遭到刪除。"</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統會重設這台平板電腦,其中的所有資料也會一併遭到刪除。"</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統會重設這支手機,其中的所有資料也會一併遭到刪除。"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,這位使用者將遭到移除,所有相關的使用者資料也會一併遭到刪除。"</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,這位使用者將遭到移除,所有相關的使用者資料也會一併遭到刪除。"</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。你的工作資料夾將遭到移除,所有設定檔資料也會一併遭到刪除。"</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。你的工作資料夾將遭到移除,所有設定檔資料也會一併遭到刪除。"</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統就會要求你透過電子郵件帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統就會要求你透過電子郵件帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM 卡的 PIN 碼輸入錯誤,你現在必須請電信業者為裝置解鎖。"</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="other">SIM 卡的 PIN 碼輸入錯誤,你還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item> diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml index 604bb9d7cbad..fe81d02acb93 100644 --- a/packages/SystemUI/res-keyguard/values-zu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml @@ -42,8 +42,6 @@ <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Chofoza Menyu ukuvula."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Inethiwekhi ivaliwe"</string> <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Alikho ikhadi le-SIM."</string> - <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Alikho ikhadi le-SIM efonini."</string> - <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Alikho ikhadi le-SIM efonini."</string> <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Faka ikhadi le-SIM."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Ikhadi le-SIM alitholakali noma alifundeki. Sicela ufake ikhadi le-SIM."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Ikhadi le-SIM elingasetshenzisiwe."</string> @@ -83,17 +81,10 @@ <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Thayipha i-PIN enezinombolo ezingu-4 kuya kwezingu-8."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Ikhodi ye-PUK kufanele ibe yizinombolo ezingu-8 noma eziningi."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Faka kabusha ikhodi ye-PUK elungile. Imizamo ephindiwe izokhubaza unaphakade i-SIM."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Iphinikhodi ayifani"</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Kunemizamo eminingi kakhulu yephathini!"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Ubhale iphinikhodi ykho ngendlela engafanele izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Ubhale iphasiwedi yakho ngendlela engafanele <xliff:g id="NUMBER_0">%1$d</xliff:g> izikhathi. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Udwebe iphathini yakho yokuvula ngendlela engafanele-<xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%2$d</xliff:g>"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, le thebulethi izosethwa kabusha, okuzosusa yonke idatha yayo."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, le foni izosethwa kabusha, okuzosusa yonke idatha yayo."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Le thebulethi izosethwa kabusha, okuzosusa yonke idatha yayo."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Le foni izosethwa kabusha, okuzosusa yonke idatha yayo."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string> - <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string> <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> <skip /> <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> @@ -102,10 +93,6 @@ <skip /> <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> <skip /> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string> - <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Udwebe ngokungalungile iphethini yakho yokuvula ngezikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphumelelanga kaningi engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuthi uvule ithebulethi yakho usebenzisa i-akhawunti ye-imeyili.\n\nZama futhi kumasekhondi angu-<xliff:g id="NUMBER_2">%3$d</xliff:g>."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%1$d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%3$d</xliff:g> imizuzwana."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Ikhodi yephinikhodi ye-SIM engalungile manje kumele uxhumane nenkampini yenethiwekhi yakho ukuvula idivayisi yakho."</string> <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026"> <item quantity="one">Ikhodi engalungile yephinikhodi ye-SIM, unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele.</item> diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index 485240a8895b..f7e9fedd5f66 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -91,10 +91,6 @@ <string name="keyguard_network_locked_message">Network locked</string> <!-- Shown when there is no SIM card. --> <string name="keyguard_missing_sim_message_short">No SIM card</string> - <!-- Shown when there is no SIM card. --> - <string name="keyguard_missing_sim_message" product="tablet">No SIM card in tablet.</string> - <!-- Shown when there is no SIM card. --> - <string name="keyguard_missing_sim_message" product="default">No SIM card in phone.</string> <!-- Shown to ask the user to insert a SIM card. --> <string name="keyguard_missing_sim_instructions">Insert a SIM card.</string> <!-- Shown to ask the user to insert a SIM card when sim is missing or not readable. --> @@ -189,8 +185,6 @@ <string name="kg_invalid_sim_puk_hint">PUK code should be 8 numbers or more.</string> <!-- Message shown when the user enters an invalid PUK code --> <string name="kg_invalid_puk">Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM.</string> - <!-- String shown in PUK screen when PIN codes don't match --> - <string name="kg_invalid_confirm_pin_hint" product="default">PIN codes does not match</string> <!-- Message shown when the user exceeds the maximum number of pattern attempts --> <string name="kg_login_too_many_attempts">Too many pattern attempts</string> <!-- Message shown in dialog when max number of attempts are reached for PIN screen of keyguard --> @@ -208,92 +202,6 @@ \n\nTry again in <xliff:g id="number">%2$d</xliff:g> seconds. </string> - <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. [CHAR LIMIT=none] --> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet"> - You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times. - After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, - this tablet will be reset, which will delete all its data. - </string> - <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. [CHAR LIMIT=none] --> - <string name="kg_failed_attempts_almost_at_wipe" product="default"> - You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times. - After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, - this phone will be reset, which will delete all its data. - </string> - <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped [CHAR LIMIT=none] --> - <string name="kg_failed_attempts_now_wiping" product="tablet"> - You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times. - This tablet will be reset, which will delete all its data. - </string> - <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped [CHAR LIMIT=none] --> - <string name="kg_failed_attempts_now_wiping" product="default"> - You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times. - This phone will be reset, which will delete all its data. - </string> - - <!-- Message shown when user is almost at the limit of password attempts where the user will be removed. [CHAR LIMIT=none] --> - <string name="kg_failed_attempts_almost_at_erase_user" product="tablet"> - You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times. - After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, - this user will be removed, which will delete all user data. - </string> - <!-- Message shown when user is almost at the limit of password attempts where the user will be removed. [CHAR LIMIT=none] --> - <string name="kg_failed_attempts_almost_at_erase_user" product="default"> - You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times. - After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, - this user will be removed, which will delete all user data. - </string> - <!-- Message shown in dialog when user has exceeded the maximum attempts and the user will be removed. [CHAR LIMIT=none] --> - <string name="kg_failed_attempts_now_erasing_user" product="tablet"> - You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times. - This user will be removed, which will delete all user data. - </string> - <!-- Message shown in dialog when user has exceeded the maximum attempts and the user will be removed. [CHAR LIMIT=none] --> - <string name="kg_failed_attempts_now_erasing_user" product="default"> - You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times. - This user will be removed, which will delete all user data. - </string> - - <!-- Message shown when user is almost at the limit of password attempts where the profile will be removed. [CHAR LIMIT=none] --> - <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet"> - You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times. - After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, - the work profile will be removed, which will delete all profile data. - </string> - <!-- Message shown when user is almost at the limit of password attempts where the profile will be removed. [CHAR LIMIT=none] --> - <string name="kg_failed_attempts_almost_at_erase_profile" product="default"> - You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times. - After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, - the work profile will be removed, which will delete all profile data. - </string> - <!-- Message shown in dialog when user has exceeded the maximum attempts and the profile will be removed. [CHAR LIMIT=none] --> - <string name="kg_failed_attempts_now_erasing_profile" product="tablet"> - You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times. - The work profile will be removed, which will delete all profile data. - </string> - <!-- Message shown in dialog when user has exceeded the maximum attempts and the profile will be removed. [CHAR LIMIT=none] --> - <string name="kg_failed_attempts_now_erasing_profile" product="default"> - You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times. - The work profile will be removed, which will delete all profile data. - </string> - - <!-- Message shown in dialog when user is almost at the limit where they will be - locked out and may have to enter an alternate username/password to unlock the phone --> - <string name="kg_failed_attempts_almost_at_login" product="tablet"> - You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times. - After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, - you will be asked to unlock your tablet using an email account.\n\n - Try again in <xliff:g id="number">%3$d</xliff:g> seconds. - </string> - <!-- Message shown in dialog when user is almost at the limit where they will be - locked out and may have to enter an alternate username/password to unlock the phone --> - <string name="kg_failed_attempts_almost_at_login" product="default"> - You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times. - After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, - you will be asked to unlock your phone using an email account.\n\n - Try again in <xliff:g id="number">%3$d</xliff:g> seconds. - </string> - <!-- Instructions telling the user that they entered the wrong SIM PIN for the last time. Displayed in a dialog box. --> <string name="kg_password_wrong_pin_code_pukked">Incorrect SIM PIN code you must now contact your carrier to unlock your device.</string> diff --git a/packages/SystemUI/res-product/values-af/strings.xml b/packages/SystemUI/res-product/values-af/strings.xml new file mode 100644 index 000000000000..61ccec87f23b --- /dev/null +++ b/packages/SystemUI/res-product/values-af/strings.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Geen SIM-kaart in tablet nie."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Geen SIM-kaart in foon nie."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-kodes stem nie ooreen nie"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie tablet teruggestel word, wat al sy data sal uitvee."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie foon teruggestel word, wat al sy data sal uitvee."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie tablet sal teruggestel word, wat al sy data sal uitvee."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie foon sal teruggestel word, wat al sy data sal uitvee."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie gebruiker verwyder word, wat alle gebruikerdata sal uitvee."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie gebruiker verwyder word, wat alle gebruikerdata sal uitvee."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Die Android TV-toestel gaan binnekort afskakel; druk \'n knoppie om dit aan te hou."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Die toestel gaan binnekort afskakel; druk om dit aan te hou."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou tablet te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou foon te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-am/strings.xml b/packages/SystemUI/res-product/values-am/strings.xml new file mode 100644 index 000000000000..4628b2b93b9a --- /dev/null +++ b/packages/SystemUI/res-product/values-am/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"በጡባዊ ውስጥ ምንም ሲም ካርድ የለም።"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"በስልክ ውስጥ ምንም ሲም ካርድ የለም።"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ፒን ኮዶቹ አይገጣጠሙም"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ጡባዊውን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ጡባዊ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂብ ይሰርዛል።"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ስልኩን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ስልክ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂብ ይሰርዛል።"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ጡባዊውን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ ሁኔታ ለማስከፈት ሞክረዋል። ስልኩ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ ሁኔታ ለማስከፈት ሞክረዋል። ስልኩ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ጡባዊውን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ስልኩን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"የAndroid TV መሣሪያው በቅርቡ ይጠፋል፣ እንደበራ ለማቆየት ይጫኑ።"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"መሣሪያው በቅርቡ ይጠፋል፤ እንደበራ ለማቆየት ይጫኑ።"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ጡባዊውን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለመክፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለመክፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ጡባዊዎን እንዲከፍቱ ይጠየቃሉ።\n\n ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ከሰከንዶች በኋላ እንደገና ይሞክሩ።"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ar/strings.xml b/packages/SystemUI/res-product/values-ar/strings.xml new file mode 100644 index 000000000000..09aa42eb2a00 --- /dev/null +++ b/packages/SystemUI/res-product/values-ar/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ليست هناك شريحة SIM في الجهاز اللوحي."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ليست هناك شريحة SIM في الهاتف."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"لا يتطابق رمز رقم التعريف الشخصي"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إعادة تعيين هذا الجهاز، ومن ثم يتم حذف جميع بياناته."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إعادة تعيين هذا الهاتف، ومن ثم يتم حذف جميع بياناته."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إعادة تعيين هذا الجهاز، ومن ثم يتم حذف جميع بياناته."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إعادة تعيين هذا الهاتف، ومن ثم يتم حذف جميع بياناته."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إزالة هذا المستخدم، ومن ثم يتم حذف جميع بيانات المستخدم."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إزالة هذا المستخدم، ومن ثم يتم حذف جميع بيانات المستخدم."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"سيتم إيقاف جهاز Android TV قريبًا، اضغط على أحد الأزرار لمواصلة تشغيله."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"سيتم إيقاف الجهاز قريبًا، اضغط لمواصلة تشغيله."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-as/strings.xml b/packages/SystemUI/res-product/values-as/strings.xml new file mode 100644 index 000000000000..1f1ca094c201 --- /dev/null +++ b/packages/SystemUI/res-product/values-as/strings.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"টেবলেটত ছিম কার্ড নাই।"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ফ\'নত ছিম কার্ড নাই।"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"পিন ক\'ড মিলা নাই"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে টেবলেটটো ৰিছেট কৰা হ\'ব, যি কার্যই টেবলেটটোত থকা সকলো ডেটা মচিব।"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে ফ\'নটো ৰিছেট কৰা হ\'ব, যি কার্যই ফ\'নটোত থকা সকলো ডেটা মচিব।"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। এই টেবলেটটো ৰিছেট কৰা হ\'ব, যি কার্যই ইয়াৰ সকলো ডেটা মচিব।"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। এই ফ\'নটো ৰিছেট কৰা হ\'ব, যিয়ে ইয়াৰ সকলো ডেটা মচিব।"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে এই ব্যৱহাৰকাৰীক আঁতৰোৱা হ\'ব, যিয়ে ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব।"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে এই ব্যৱহাৰকাৰীক আঁতৰোৱা হ\'ব, যিয়ে ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব।"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for notification_bubble_title (8330481035191903164) --> + <skip/> + <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ডিভাইচটো অতি সোনকালে অফ হ\'ব, এইটো অন ৰাখিবলৈ যিকোনো এটা বুটাম টিপক।"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"এই ডিভাইচটো অতি সোনকালে অফ হ\'ব, এইটো অন ৰাখিবলৈ টিপক।"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলটো আঁতৰোৱা হ\'ব, যি কার্যই প্ৰ\'ফাইলটোৰ সকলো ডেটা মচিব।"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলটো আঁতৰোৱা হ\'ব, যিয়ে প্ৰ\'ফাইলটোৰ সকলো ডেটা মচিব।"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"আপুনি আপোনাৰ আনলক আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল আৰ্হি আঁকিলে আপোনাৰ টেবলেটটো কোনো একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ\'ব।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"আপুনি আপোনাৰ আনলক আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল আৰ্হি আঁকিলে আপোনাৰ ফ\'নটো কোনো একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ\'ব।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-az/strings.xml b/packages/SystemUI/res-product/values-az/strings.xml new file mode 100644 index 000000000000..c34b1422e07a --- /dev/null +++ b/packages/SystemUI/res-product/values-az/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planşetdə SIM kart yoxdur."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonda SIM kart yoxdur."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodlar uyğun gəlmir"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu planşet sıfırlanacaq və bütün data silinəcək."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu telefon sıfırlanacaq və bütün data silinəcək."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Bu planşet sıfırlanacaq və bütün data silinəcək."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Bu telefon sıfırlanacaq və bütün data silinəcək."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu istifadəçi silinəcək və bütün istifadəçi datası ləğv ediləcək."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu istifadəçi silinəcək və bütün istifadəçi datası ləğv ediləcək."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV cihazı tezliklə sönəcək; aktiv saxlamaq üçün düyməyə basın."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Cihaz tezliklə sönəcək; aktiv saxlamaq üçün basın."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml new file mode 100644 index 000000000000..e753e74703b9 --- /dev/null +++ b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"U tabletu nema SIM kartice."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"U telefonu nema SIM kartice."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodovi se ne podudaraju"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, ovaj tablet će se resetovati, čime se brišu svi podaci korisnika."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, ovaj telefon će se resetovati, čime se brišu svi podaci korisnika."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Ovaj tablet će se resetovati, čime se brišu svi podaci."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Ovaj telefon će se resetovati, čime se brišu svi podaci."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo ovog korisnika, čime se brišu svi podaci korisnika."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo ovog korisnika, čime se brišu svi podaci korisnika."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV će se uskoro isključiti. Pritisnite dugme da bi ostao uključen."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Uređaj će se uskoro isključiti. Pritisnite da bi ostao uključen."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo profil za Work, čime se brišu svi podaci sa profila."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo profil za Work, čime se brišu svi podaci sa profila."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate tablet pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate telefon pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-be/strings.xml b/packages/SystemUI/res-product/values-be/strings.xml new file mode 100644 index 000000000000..e2dbd245cc39 --- /dev/null +++ b/packages/SystemUI/res-product/values-be/strings.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"У планшэце няма SIM-карты."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"У тэлефоне няма SIM-карты."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коды не супадаюць"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Цяпер ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Цяпер ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) гэты карыстальнік будзе выдалены, гэта прывядзе да выдалення ўсіх карыстальніцкіх даных."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) гэты карыстальнік будзе выдалены, гэта прывядзе да выдалення ўсіх карыстальніцкіх даных."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- String.format failed for translation --> + <!-- no translation found for accessibility_battery_level (5143715405241138822) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Прылада Android TV неўзабаве выключыцца. Каб пакінуць яе ўключанай, націсніце кнопку."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Прылада неўзабаве выключыцца. Націсніце, каб пакінуць яе ўключанай."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, гэта прывядзе да выдалення ўсіх даных у профілі."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, гэта прывядзе да выдалення ўсіх даных у профілі."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць планшэт, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць тэлефон, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-bg/strings.xml b/packages/SystemUI/res-product/values-bg/strings.xml new file mode 100644 index 000000000000..4ae6d4c50670 --- /dev/null +++ b/packages/SystemUI/res-product/values-bg/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"В таблета няма SIM карта."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"В телефона няма SIM карта."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ПИН кодовете не съвпадат"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита той ще бъде нулиран, при което ще се изтрият всичките му данни."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита той ще бъде нулиран, при което ще се изтрият всичките му данни."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Той ще бъде нулиран, при което ще се изтрият всичките му данни."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Той ще бъде нулиран, при което ще се изтрият всичките му данни."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Устройството с Android TV скоро ще се изключи. Натиснете бутон, за да остане включено."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Устройството скоро ще се изключи. Натиснете, за да остане включено."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета си посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-bn/strings.xml b/packages/SystemUI/res-product/values-bn/strings.xml new file mode 100644 index 000000000000..260f7bca8ba5 --- /dev/null +++ b/packages/SystemUI/res-product/values-bn/strings.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ট্যাবলেটের মধ্যে কোনো সিম কার্ড নেই।"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ফোনের মধ্যে কোনো সিম কার্ড নেই।"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"পিন কোডগুলি মিলছে না"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ট্যাবলেটটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ফোনটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। এই ফোনটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। এই ফোনটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ব্যবহারকারীকে সরিয়ে দেওয়া হবে, যার ফলে ব্যবহারকারীর সমস্ত ডেটা মুছে যাবে।"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ব্যবহারকারীকে সরিয়ে দেওয়া হবে, যার ফলে ব্যবহারকারীর সমস্ত ডেটা মুছে যাবে।"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for notification_bubble_title (8330481035191903164) --> + <skip/> + <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ডিভাইস শীঘ্রই বন্ধ হয়ে যাবে, চালু রাখতে বোতাম প্রেস করুন।"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ডিভাইস শীঘ্রই বন্ধ হয়ে যাবে, চালু রাখতে প্রেস করুন।"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। কাজের প্রোফাইলটি সরিয়ে দেওয়া হবে, যার ফলে প্রোফাইলের সমস্ত ডেটা মুছে যাবে।"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। কাজের প্রোফাইলটি সরিয়ে দেওয়া হবে, যার ফলে প্রোফাইলের সমস্ত ডেটা মুছে যাবে।"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে আনলকের প্যাটার্ন এঁকেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর আপনাকে একটি ইমেল অ্যাকাউন্টের মাধ্যমে আপনার ট্যাবলেটটি আনলক করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে আনলকের প্যাটার্ন এঁকেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর আপনাকে একটি ইমেল অ্যাকাউন্টের মাধ্যমে আপনার ফোনটি আনলক করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-bs/strings.xml b/packages/SystemUI/res-product/values-bs/strings.xml new file mode 100644 index 000000000000..b9beecf3f0f5 --- /dev/null +++ b/packages/SystemUI/res-product/values-bs/strings.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nema SIM kartice u tabletu."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nema SIM kartice u telefonu."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-ovi se ne poklapaju"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati tablet. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, tablet će se vratiti na fabričke postavke i svi podaci će se izbrisati."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, telefon će se vratiti na fabričke postavke i svi podaci će se izbrisati."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Tablet će se sada vratiti na fabričke postavke i svi podaci će se izbrisati."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati telefon. Telefon će se sada vratiti na fabričke postavke i svi podaci će se izbrisati."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati tablet. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, ovaj korisnik će se ukloniti i svi podaci korisnika će se izbrisati."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, ovaj korisnik će se ukloniti i svi podaci korisnika će se izbrisati."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- String.format failed for translation --> + <!-- no translation found for volume_stream_content_description_unmute (7729576371406792977) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV uređaj će se uskoro isključiti. Pritisnite dugme da ostane uključen."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Uređaj će se uskoro isključiti. Pritisnite da ostane uključen."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Poslovni profil će se ukloniti i svi podaci s profila će se izbrisati."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati telefon. Poslovni profil će se ukloniti i svi podaci s profila će se izbrisati."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da tablet otključate koristeći račun e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da telefon otključate koristeći račun e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ca/strings.xml b/packages/SystemUI/res-product/values-ca/strings.xml new file mode 100644 index 000000000000..20d8e2fc1fec --- /dev/null +++ b/packages/SystemUI/res-product/values-ca/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No hi ha cap SIM a la tauleta."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No hi ha cap SIM al telèfon."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Els codis PIN no coincideixen"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, la tauleta es restablirà i se\'n suprimiran totes les dades."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, el telèfon es restablirà i se\'n suprimiran totes les dades."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. La tauleta es restablirà i se\'n suprimiran totes les dades."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El telèfon es restablirà i se\'n suprimiran totes les dades."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, l\'usuari se suprimirà, juntament amb totes les seves dades."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, l\'usuari se suprimirà, juntament amb totes les seves dades."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"El dispositiu Android TV s\'apagarà aviat; prem un botó per mantenir-lo encès."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"El dispositiu s\'apagarà aviat; prem per mantenir-lo encès."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-cs/strings.xml b/packages/SystemUI/res-product/values-cs/strings.xml new file mode 100644 index 000000000000..feb3d950bb59 --- /dev/null +++ b/packages/SystemUI/res-product/values-cs/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"V tabletu není SIM karta."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"V telefonu není SIM karta."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kódy PIN se neshodují"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tablet resetován, čímž se z něj smažou všechna data."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude telefon resetován, čímž se z něj smažou všechna data."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Tablet bude resetován, čímž z něj budou smazána všechna data."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Telefon bude resetován, čímž z něj budou smazána všechna data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tento uživatel odstraněn, čímž se smažou všechna jeho data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tento uživatel odstraněn, čímž se smažou všechna jeho data."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Zařízení Android TV se brzy vypne, stisknutím tlačítka ho ponecháte zapnuté."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Zařízení se brzy vypne, stisknutím ho ponecháte zapnuté."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-da/strings.xml b/packages/SystemUI/res-product/values-da/strings.xml new file mode 100644 index 000000000000..0a7135c40776 --- /dev/null +++ b/packages/SystemUI/res-product/values-da/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Der er ikke noget SIM-kort i denne tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Der er ikke noget SIM-kort i telefonen."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Pinkoderne stemmer ikke overens"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du har forsøgt at låse denne tablet op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg nulstilles denne tablet, hvilket sletter alle dens data."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du har forsøgt at låse telefonen op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg nulstilles denne telefon, hvilket sletter alle dens data."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du har forsøgt at låse denne tablet op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Denne tablet nulstilles, hvilket sletter alle dens data."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du har forsøgt at låse telefonen op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Telefonen nulstilles, hvilket sletter alle dens data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du har forsøgt at låse denne tablet op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket sletter alle brugerdata."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du har forsøgt at låse telefonen op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket sletter alle brugerdata."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV-enheden slukker snart. Tryk på en knap for at holde den tændt."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Enheden slukker snart. Tryk for at holde den tændt."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du har forsøgt at låse denne tablet op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket sletter alle profildata."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du har forsøgt at låse telefonen op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket sletter alle profildata."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din tablet op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din telefon op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-de/strings.xml b/packages/SystemUI/res-product/values-de/strings.xml new file mode 100644 index 000000000000..0c0c5138be9d --- /dev/null +++ b/packages/SystemUI/res-product/values-de/strings.xml @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Keine SIM-Karte im Tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Keine SIM-Karte im Telefon."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-Codes stimmen nicht überein"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieses Tablet zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieses Telefon zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Dieses Tablet wird nun zurückgesetzt und alle Gerätedaten werden gelöscht."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Dieses Telefon wird nun zurückgesetzt und alle Gerätedaten werden gelöscht."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieser Nutzer entfernt. Dadurch werden alle Nutzerdaten gelöscht."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieser Nutzer entfernt. Dadurch werden alle Nutzerdaten gelöscht."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- String.format failed for translation --> + <!-- no translation found for accessibility_battery_level (5143715405241138822) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- String.format failed for translation --> + <!-- no translation found for accessibility_battery_level_charging (8892191177774027364) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Das Android TV-Gerät wird demnächst abgeschaltet. Drücke eine Taste, damit es eingeschaltet bleibt."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Das Gerät wird demnächst abgeschaltet. Drücke beispielsweise eine Taste oder berühre den Bildschirm, damit es eingeschaltet bleibt."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-el/strings.xml b/packages/SystemUI/res-product/values-el/strings.xml new file mode 100644 index 000000000000..cd76dac0879f --- /dev/null +++ b/packages/SystemUI/res-product/values-el/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Δεν υπάρχει κάρτα SIM στο tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Δεν υπάρχει κάρτα SIM στο τηλέφωνο."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Δεν υπάρχει αντιστοιχία μεταξύ των κωδικών PIN"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτό το tablet θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτό το τηλέφωνο θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Δοκιμάσατε να ξεκλειδώσετε αυτό το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτό το tablet θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτό το τηλέφωνο θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτός ο χρήστης θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα χρήστη."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτός ο χρήστης θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα χρήστη."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Η συσκευή Android TV σύντομα θα απενεργοποιηθεί. Πατήστε ένα κουμπί για να την κρατήσετε ενεργοποιημένη."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Η συσκευή σύντομα θα απενεργοποιηθεί. Πατήστε για να την κρατήσετε ενεργοποιημένη."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα προφίλ."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα προφίλ."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το tablet με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-en-rAU/strings.xml b/packages/SystemUI/res-product/values-en-rAU/strings.xml new file mode 100644 index 000000000000..9e8ed2f23309 --- /dev/null +++ b/packages/SystemUI/res-product/values-en-rAU/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-en-rCA/strings.xml b/packages/SystemUI/res-product/values-en-rCA/strings.xml new file mode 100644 index 000000000000..9e8ed2f23309 --- /dev/null +++ b/packages/SystemUI/res-product/values-en-rCA/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-en-rGB/strings.xml b/packages/SystemUI/res-product/values-en-rGB/strings.xml new file mode 100644 index 000000000000..9e8ed2f23309 --- /dev/null +++ b/packages/SystemUI/res-product/values-en-rGB/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-en-rIN/strings.xml b/packages/SystemUI/res-product/values-en-rIN/strings.xml new file mode 100644 index 000000000000..9e8ed2f23309 --- /dev/null +++ b/packages/SystemUI/res-product/values-en-rIN/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-en-rXC/strings.xml b/packages/SystemUI/res-product/values-en-rXC/strings.xml new file mode 100644 index 000000000000..28062888d376 --- /dev/null +++ b/packages/SystemUI/res-product/values-en-rXC/strings.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string> +<string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes does not match"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string> + <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="9046628517316763961">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This user will be removed, which will delete all user data."</string> + <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="3588779327358321092">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This user will be removed, which will delete all user data."</string> + <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="6114158710353725041">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string> + <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="8345451368768804892">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-es-rUS/strings.xml b/packages/SystemUI/res-product/values-es-rUS/strings.xml new file mode 100644 index 000000000000..85d3dbaee64c --- /dev/null +++ b/packages/SystemUI/res-product/values-es-rUS/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No hay tarjeta SIM en la tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No hay tarjeta SIM en el teléfono."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Los códigos PIN no coinciden"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá la tablet, lo que borrará todos los datos."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá el teléfono, lo que borrará todos los datos."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se restablecerá la tablet, lo que borrará todos los datos."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se restablecerá el teléfono, lo que borrará todos los datos."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se quitará este usuario, lo que borrará todos los datos asociados."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se quitará este usuario, lo que borrará todos los datos asociados."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Pronto se apagará el dispositivo Android TV; presiona un botón para mantenerlo encendido."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Pronto se apagará el dispositivo; presiona para mantenerlo encendido."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se quitará el perfil de trabajo, lo que borrará todos los datos asociados."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se quitará el perfil de trabajo, lo que borrará todos los datos asociados."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tablet mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-es/strings.xml b/packages/SystemUI/res-product/values-es/strings.xml new file mode 100644 index 000000000000..ed94cb27ea00 --- /dev/null +++ b/packages/SystemUI/res-product/values-es/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No se ha insertado ninguna tarjeta SIM en el tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No se ha insertado ninguna tarjeta SIM en el teléfono."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Los códigos PIN no coinciden"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el tablet. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se recuperarán los ajustes de fábrica de este tablet y se eliminarán todos sus datos."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el teléfono. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se recuperarán los ajustes de fábrica de este teléfono y se eliminarán todos sus datos."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el tablet. Se recuperarán los ajustes de fábrica de este tablet y se eliminarán todos sus datos."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el teléfono. Se recuperarán los ajustes de fábrica de este teléfono y se eliminarán todos sus datos."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el tablet. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se quitará a este usuario y se eliminarán todos sus datos."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el teléfono. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se quitará a este usuario y se eliminarán todos sus datos."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"El dispositivo Android TV pronto se apagará; pulsa un botón para evitarlo."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"El dispositivo pronto se apagará si no interactúas con él."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el tablet. Se quitará este perfil de trabajo se quitará y se eliminarán todos sus datos."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el teléfono. Se quitará este perfil de trabajo y se eliminarán todos sus datos."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, tendrás que usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, tendrás que usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-et/strings.xml b/packages/SystemUI/res-product/values-et/strings.xml new file mode 100644 index 000000000000..1c4688ae325a --- /dev/null +++ b/packages/SystemUI/res-product/values-et/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tahvelarvutis pole SIM-kaarti."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonis pole SIM-kaarti."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-koodid ei ole vastavuses"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset tahvelarvuti lähtestatakse ja kõik selle andmed kustutatakse."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset telefon lähtestatakse ja kõik selle andmed kustutatakse."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda tahvelarvutit valesti avada. Tahvelarvuti lähtestatakse ja kõik selle andmed kustutatakse."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda telefoni valesti avada. Telefon lähtestatakse ja kõik selle andmed kustutatakse."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutajaandmed kustutatakse."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutajaandmed kustutatakse."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV seade lülitub varsti välja; selle aktiivsena hoidmiseks vajutage nuppu."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Seade lülitub värsti välja; selle aktiivsena hoidmiseks vajutage nuppu."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda tahvelarvutit valesti avada. Tööprofiil eemaldatakse ja kõik profiiliandmed kustutatakse."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda telefoni valesti avada. Tööprofiil eemaldatakse ja kõik profiiliandmed kustutatakse."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-eu/strings.xml b/packages/SystemUI/res-product/values-eu/strings.xml new file mode 100644 index 000000000000..265400abaa22 --- /dev/null +++ b/packages/SystemUI/res-product/values-eu/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Ez dago SIM txartelik tabletan."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Ez dago SIM txartelik telefonoan."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodeak ez datoz bat"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, berrezarri egingo da tableta eta, ondorioz, bertako datu guztiak ezabatuko dira."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, berrezarri egingo da telefonoa eta, ondorioz, bertako datu guztiak ezabatuko dira."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Tableta berrezarri egingo da eta, ondorioz, bertako datu guztiak ezabatuko dira."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Telefonoa berrezarri egingo da eta, ondorioz, bertako datu guztiak ezabatuko dira."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, kendu egingo da erabiltzailea eta, ondorioz, haren datu guztiak ezabatuko dira."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, kendu egingo da erabiltzailea eta, ondorioz, haren datu guztiak ezabatuko dira."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV gailua laster itzaliko da; sakatu botoi bat piztuta mantentzeko."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Gailua laster itzaliko da; sakatu piztuta mantentzeko."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz marraztu duzu desblokeatzeko eredua, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, tableta posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz marraztu duzu desblokeatzeko eredua, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-fa/strings.xml b/packages/SystemUI/res-product/values-fa/strings.xml new file mode 100644 index 000000000000..018c17dd22bf --- /dev/null +++ b/packages/SystemUI/res-product/values-fa/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"سیمکارت درون رایانهٔ لوحی نیست."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"سیمکارت درون تلفن نیست."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"کدهای پین منطبق نیستند"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، این رایانه لوحی بازنشانی میشود که با آن همه دادههایش حذف میشود."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، تلفن بازنشانی میشود که با آن همه دادههایش حذف میشود."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. این رایانه لوحی بازنشانی میشود که با آن همه دادههایش حذف میشود."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. این تلفن بازنشانی میشود که با آن همه دادههایش حذف میشود."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، این کاربر پاک میشود که با آن همه دادههای کاربر حذف میشود."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، این کاربر پاک میشود که با آن همه دادههای کاربر حذف میشود."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"دستگاه Android TV بهزودی خاموش میشود، برای روشن نگهداشتن آن، دکمهای را فشار دهید."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"دستگاه بهزودی خاموش میشود، برای روشن نگهداشتن آن فشار دهید."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. نمایه کاری پاک میشود که با آن همه دادههای نمایه حذف میشود."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. نمایه کاری پاک میشود که با آن همه دادههای نمایه حذف میشود."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. بعد از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل تلفن را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-fi/strings.xml b/packages/SystemUI/res-product/values-fi/strings.xml new file mode 100644 index 000000000000..377b577e3823 --- /dev/null +++ b/packages/SystemUI/res-product/values-fi/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tabletissa ei ole SIM-korttia."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Puhelimessa ei ole SIM-korttia."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-koodit eivät täsmää"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä tabletti nollataan ja kaikki sen tiedot poistetaan."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä käyttäjä ja kaikki sen käyttäjätiedot poistetaan."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä käyttäjä ja kaikki käyttäjän tiedot poistetaan."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ‑laite sammuu pian. Pidä se päällä painamalla painiketta."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Laite sammuu pian. Pidä se päällä painamalla jotakin."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen tiedot poistetaan."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen tiedot poistetaan."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan tabletin lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-fr-rCA/strings.xml b/packages/SystemUI/res-product/values-fr-rCA/strings.xml new file mode 100644 index 000000000000..44299379cb32 --- /dev/null +++ b/packages/SystemUI/res-product/values-fr-rCA/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Aucune carte SIM n\'est insérée dans la tablette."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Aucune carte SIM n\'est insérée dans le téléphone."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Les NIP ne correspondent pas."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cette tablette sera réinitialisée, ce qui entraînera la suppression de toutes les données qu\'elle contient."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), le téléphone sera réinitialisé, ce qui entraînera la suppression de toutes les données qu\'il contient."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Cette tablette sera réinitialisée, ce qui entraîne la suppression de toutes les données qu\'elle contient."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Ce téléphone sera réinitialisé, ce qui entraîne la suppression de toutes les données qu\'il contient."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cet utilisateur sera supprimé, ce qui entraînera la suppression de toutes ses données."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cet utilisateur sera supprimé, ce qui entraînera la suppression de toutes ses données."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"L\'appareil Android TV va bientôt s\'éteindre. Appuyez sur un bouton pour le laisser allumé."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"L\'appareil va bientôt s\'éteindre. Interagissez avec lui pour le laisser allumé."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-fr/strings.xml b/packages/SystemUI/res-product/values-fr/strings.xml new file mode 100644 index 000000000000..2838c02d538d --- /dev/null +++ b/packages/SystemUI/res-product/values-fr/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Aucune carte SIM n\'est insérée dans la tablette."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Aucune carte SIM n\'est insérée dans le téléphone."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Les codes PIN ne correspondent pas"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, elle sera réinitialisée et toutes les données qu\'elle contient seront supprimées."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, il sera réinitialisé et toutes les données qu\'il contient seront supprimées."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Elle va être réinitialisée et toutes les données qu\'elle contient seront supprimées."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Il va être réinitialisé et toutes les données qu\'il contient seront supprimées."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, ce compte utilisateur et toutes les données associées seront supprimés."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, ce compte utilisateur et toutes les données associées seront supprimés."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"L\'appareil Android TV va bientôt passer en mode Veille. Appuyez sur un bouton pour qu\'il reste allumé."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"L\'appareil va bientôt passer en mode Veille. Appuyez dessus pour qu\'il reste allumé."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-gl/strings.xml b/packages/SystemUI/res-product/values-gl/strings.xml new file mode 100644 index 000000000000..b1e045f1a0e2 --- /dev/null +++ b/packages/SystemUI/res-product/values-gl/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Non hai ningunha tarxeta SIM na tableta."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Non hai ningunha tarxeta SIM no teléfono."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN non coinciden"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tentaches desbloquear a tableta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, restablecerase a tableta e, por conseguinte, eliminaranse todos os seus datos."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, restablecerase o teléfono e, por conseguinte, eliminaranse todos os seus datos."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tentaches desbloquear a tableta <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Restablecerase a tableta e, por conseguinte, eliminaranse todos os seus datos."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Restablecerase o teléfono e, por conseguinte, eliminaranse todos os seus datos."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tentaches desbloquear a tableta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, quitarase este usuario e, por conseguinte, todos os datos do usuario."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, quitarase este usuario e, por conseguinte, todos os datos do usuario."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Pronto se apagará o dispositivo Android TV. Preme un botón para mantelo acendido."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Pronto se apagará o dispositivo. Tócao para mantelo acendido."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tentaches desbloquear a tableta <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Quitarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Quitarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear a tableta a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-gu/strings.xml b/packages/SystemUI/res-product/values-gu/strings.xml new file mode 100644 index 000000000000..1a9228ed0e79 --- /dev/null +++ b/packages/SystemUI/res-product/values-gu/strings.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ટૅબ્લેટમાં સિમ કાર્ડ નથી."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ફોનમાં સિમ કાર્ડ નથી."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"પિન કોડ મેળ ખાતા નથી"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"તમે ટૅબ્લેટને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, આ ટૅબ્લેટ ફરીથી સેટ કરવામાં આવશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"તમે ફોનને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, આ ફોન ફરીથી સેટ કરવામાં આવશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"તમે ટૅબ્લેટને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ ટૅબ્લેટ ફરીથી સેટ થશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"તમે ફોનને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ ફોન ફરીથી સેટ કરાશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"તમે ટૅબ્લેટને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. <xliff:g id="NUMBER_1">%2$d</xliff:g> વધુ અસફળ પ્રયાસો પછી, આ વપરાશકર્તાને દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટાને કાઢી નાખશે."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"તમે ફોનને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, આ વપરાશકર્તાને દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટા કાઢી નાખશે."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for notification_bubble_title (8330481035191903164) --> + <skip/> + <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android ટીવી ડિવાઇસ ટૂંક સમયમાં બંધ થશે; તેને ચાલુ રાખવા માટે બટન દબાવો."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ડિવાઇસ ટૂંક સમયમાં બંધ થશે; તેને ચાલુ રાખવા માટે દબાવો."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"તમે ટૅબ્લેટને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ કાર્યાલયની પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"તમે ફોનને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ કાર્યાલયની પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને એક ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ટૅબ્લેટને અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરી પ્રયાસ કરો."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને ફોન અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-hi/strings.xml b/packages/SystemUI/res-product/values-hi/strings.xml new file mode 100644 index 000000000000..7babf18dc0f9 --- /dev/null +++ b/packages/SystemUI/res-product/values-hi/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"टैबलेट में कोई SIM कार्ड नहीं है."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"फ़ोन में कोई SIM कार्ड नहीं है."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"पिन कोड का मिलान नहीं हो रहा है"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल कोशिशों के बाद, इस टैबलेट को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल कोशिशों के बाद, इस फ़ोन को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. इस टैबलेट को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. इस फ़ोन को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"आपने टैबलेट का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर, इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा मिट जाएगा."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"आपने फ़ोन का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर, इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा मिट जाएगा."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV डिवाइस जल्द ही बंद हो जाएगा. इसे चालू रखने के लिए किसी बटन को दबाएं."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"डिवाइस जल्द ही बंद हो जाएगा. इसे चालू रखने के लिए स्क्रीन पर टैप करें या किसी बटन को दबाएं."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. वर्क प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. वर्क प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"आपने अपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से ड्रॉ किया है. अगर आपने <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत ड्रॉ किया, तो आपसे अपने टैबलेट को किसी ईमेल खाते का इस्तेमाल करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड बाद फिर से कोशिश करें."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"आपने अपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से ड्रॉ किया है. अगर आपने <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत ड्रॉ किया, तो आपसे अपने फ़ोन को किसी ईमेल खाते का इस्तेमाल करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड बाद फिर से कोशिश करें."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-hr/strings.xml b/packages/SystemUI/res-product/values-hr/strings.xml new file mode 100644 index 000000000000..690f58a28acd --- /dev/null +++ b/packages/SystemUI/res-product/values-hr/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"U tabletu nema SIM kartice."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"U telefonu nema SIM kartice."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodovi nisu jednaki"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja tablet će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja telefon će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER">%d</xliff:g> put/a. Tablet će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> put/a. Telefon će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Uređaj Android TV uskoro će se isključiti. Pritisnite gumb da bi ostao uključen."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Uređaj će se uskoro isključiti. Pritisnite da bi ostao uključen."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER">%d</xliff:g> put/a. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> put/a. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati tablet pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-hu/strings.xml b/packages/SystemUI/res-product/values-hu/strings.xml new file mode 100644 index 000000000000..26160e4158e7 --- /dev/null +++ b/packages/SystemUI/res-product/values-hu/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nincs SIM-kártya a táblagépben."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nincs SIM-kártya a telefonban."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"A PIN-kódok nem egyeznek"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer visszaállítja a táblagépet, és ezzel az összes adat törlődik róla."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer visszaállítja a telefont, és ezzel az összes adat törlődik róla."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. A rendszer visszaállítja a táblagépet, és ezzel a rajta lévő összes adat törlődik."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer visszaállítja a telefont, és ezzel a rajta lévő összes adat törlődik."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer eltávolítja a felhasználót, és ezzel a felhasználó összes adata törlődik majd."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer eltávolítja a felhasználót, és ezzel a felhasználó összes adata törlődik majd."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Az Android TV eszköz hamarosan kikapcsol. Nyomja meg valamelyik gombot, hogy bekapcsolva tarthassa."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Az eszköz hamarosan kikapcsol. Nyomja meg, hogy bekapcsolva tarthassa."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. A rendszer eltávolítja a munkaprofilt, és ezzel a profil összes adata törlődik."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer eltávolítja a munkaprofilt, és ezzel a profil összes adata törlődik."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania táblagépét.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania telefonját.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-hy/strings.xml b/packages/SystemUI/res-product/values-hy/strings.xml new file mode 100644 index 000000000000..008ac7efc89a --- /dev/null +++ b/packages/SystemUI/res-product/values-hy/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Պլանշետում SIM քարտ չկա:"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Հեռախոսում SIM քարտ չկա:"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN կոդերը չեն համընկնում"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս պլանշետը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս հեռախոսը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Այս պլանշետը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Այս հեռախոսը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV սարքը շուտով կանջատվի: Սեղմեք որևէ կոճակ՝ միացրած թողնելու համար:"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Սարքը շուտով կանջատվի: Սեղմեք՝ միացրած թողնելու համար:"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Դուք կատարել եք ապակողպման նախշը մուտքագրելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել պլանշետը էլփոստի հաշվի միջոցով։\n\n Խնդրում ենք փորձել կրկին <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Դուք կատարել եք ապակողպման նախշը մուտքագրելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել հեռախոսը էլփոստի հաշվի միջոցով։\n\n Խնդրում ենք փորձել կրկին <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-in/strings.xml b/packages/SystemUI/res-product/values-in/strings.xml new file mode 100644 index 000000000000..e87aab3edbc5 --- /dev/null +++ b/packages/SystemUI/res-product/values-in/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tidak ada kartu SIM dalam tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Tidak ada Kartu SIM di dalam ponsel."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kode PIN tidak cocok"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, tablet ini akan disetel ulang, sehingga semua datanya akan dihapus."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, ponsel ini akan disetel ulang, sehingga semua datanya akan dihapus."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Tablet ini akan disetel ulang, sehingga menghapus semua datanya."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Ponsel ini akan disetel ulang, sehingga menghapus semua datanya."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Perangkat Android TV akan segera dinonaktifkan; tekan tombol untuk terus menyalakannya."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Perangkat akan segera dinonaktifkan, tekan untuk terus menyalakannya."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Profil kerja akan dihapus, sehingga menghapus semua data profil."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Profil kerja akan dihapus, sehingga menghapus semua data profil."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka. Setelah gagal <xliff:g id="NUMBER_1">%2$d</xliff:g> kali lagi, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka. Setelah gagal <xliff:g id="NUMBER_1">%2$d</xliff:g> kali lagi, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-is/strings.xml b/packages/SystemUI/res-product/values-is/strings.xml new file mode 100644 index 000000000000..38c651a05d8c --- /dev/null +++ b/packages/SystemUI/res-product/values-is/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Ekkert SIM-kort í spjaldtölvunni."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Ekkert SIM-kort í símanum."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-númerin stemma ekki"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður spjaldtölvan endurstillt, með þeim afleiðingum að öllum gögnum hennar verður eytt."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður síminn endurstilltur, með þeim afleiðingum að öllum gögnum hans verður eytt."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Spjaldtölvan verður endurstillt, með þeim afleiðingum að öllum gögnum hennar verður eytt."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Síminn verður endurstilltur, með þeim afleiðingum að öllum gögnum hans verður eytt."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður notandinn fjarlægður með þeim afleiðingum að öllum notandagögnum verður eytt."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður notandinn fjarlægður með þeim afleiðingum að öllum notandagögnum verður eytt."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV tækið slekkur á sér fljótlega. Ýttu á takka til að það slokkni ekki á því."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Tækið slekkur á sér fljótlega. Ýttu á takka til að það slokkni ekki á því."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna spjaldtölvuna með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verðurðu beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-it/strings.xml b/packages/SystemUI/res-product/values-it/strings.xml new file mode 100644 index 000000000000..1ca5706d2004 --- /dev/null +++ b/packages/SystemUI/res-product/values-it/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nessuna scheda SIM presente nel tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nessuna scheda SIM presente nel telefono."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"I codici PIN non corrispondono"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, il tablet verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, il telefono verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il tablet verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il telefono verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"A breve il dispositivo Android TV si spegnerà. Premi un pulsante per tenerlo acceso."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"A breve il dispositivo si spegnerà. Premi per tenerlo acceso."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-iw/strings.xml b/packages/SystemUI/res-product/values-iw/strings.xml new file mode 100644 index 000000000000..3a6f6f130b35 --- /dev/null +++ b/packages/SystemUI/res-product/values-iw/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"אין כרטיס SIM בטאבלט."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"אין כרטיס SIM בטלפון."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"קודי הגישה אינם תואמים"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, טאבלט זה יאופס וכל הנתונים שבו יימחקו."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, טלפון זה יאופס וכל הנתונים שבו יימחקו."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER">%d</xliff:g> פעמים. הטאבלט יאופס וכל הנתונים שלו יימחקו."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים. הטלפון יאופס וכל הנתונים שבו יימחקו."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, משתמש זה יוסר וכל נתוני המשתמש יימחקו."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, משתמש זה יוסר וכל נתוני המשתמש יימחקו."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"מכשיר Android TV ייכבה בקרוב. יש ללחוץ על לחצן כלשהו כדי שהוא ימשיך לפעול."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"המכשיר ייכבה בקרוב, יש ללחוץ כדי שהוא ימשיך לפעול."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER">%d</xliff:g> פעמים. פרופיל העבודה יוסר וכל נתוני הפרופיל יימחקו."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים. פרופיל העבודה יוסר וכל נתוני הפרופיל יימחקו."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטאבלט באמצעות חשבון אימייל.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטלפון באמצעות חשבון אימייל.\n\n נסה שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ja/strings.xml b/packages/SystemUI/res-product/values-ja/strings.xml new file mode 100644 index 000000000000..b0ea11c58698 --- /dev/null +++ b/packages/SystemUI/res-product/values-ja/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"タブレットに SIM カードが挿入されていません。"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"スマートフォンに SIM カードが挿入されていません。"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN コードが一致しません"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"タブレットのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このタブレットはリセットされ、データはすべて消去されます。"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"スマートフォンのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このスマートフォンはリセットされ、データはすべて消去されます。"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"タブレットのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。このタブレットはリセットされ、データはすべて消去されます。"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"スマートフォンのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。このスマートフォンはリセットされ、データはすべて消去されます。"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"タブレットのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このユーザーは削除され、ユーザー データはすべて消去されます。"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"スマートフォンのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このユーザーは削除され、ユーザー データはすべて消去されます。"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV デバイスはまもなく OFF になります。ON 状態を維持するには、ボタンを押してください。"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"このデバイスはまもなく OFF になります。ON 状態を維持するには、ボタンを押してください。"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"タブレットのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。仕事用プロファイルは削除され、プロファイルのデータはすべて消去されます。"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"スマートフォンのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。仕事用プロファイルは削除され、プロファイルのデータはすべて消去されます。"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、タブレットのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、スマートフォンのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ka/strings.xml b/packages/SystemUI/res-product/values-ka/strings.xml new file mode 100644 index 000000000000..1f5a20229ebb --- /dev/null +++ b/packages/SystemUI/res-product/values-ka/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ტაბლეტში არ არის SIM ბარათი."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ტელეფონში არ არის SIM ბარათი."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-კოდები არ ემთხვევა"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამ ტაბლეტის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამ ტელეფონის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, ამ ტაბლეტის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, ამ ტელეფონის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ეს მომხმარებელი ამოიშლება, რაც მომხმარებლის ყველა მონაცემის წაშლას გამოიწვევს."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ეს მომხმარებელი ამოიშლება, რაც მომხმარებლის ყველა მონაცემის წაშლას გამოიწვევს."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV მოწყობილობა მალე გამოირთვება, დააჭირეთ ღილაკს, რომ ჩართული დარჩეს."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"მოწყობილობა მალე გამოირთვება, დააჭირეთ, რომ ჩართული დარჩეს."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, სამსახურის პროფილი ამოიშლება, რაც პროფილის ყველა მონაცემის წაშლას გამოიწვევს."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, სამსახურის პროფილი ამოიშლება, რაც პროფილის ყველა მონაცემის წაშლას გამოიწვევს."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ტაბლეტის განბლოკვა თქვენი ელფოსტის ანგარიშის მეშვეობით მოგიწევთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ტელეფონის განბლოკვა თქვენი ელფოსტის ანგარიშის მეშვეობით მოგიწევთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-kk/strings.xml b/packages/SystemUI/res-product/values-kk/strings.xml new file mode 100644 index 000000000000..8185a1630711 --- /dev/null +++ b/packages/SystemUI/res-product/values-kk/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Планшетте SIM картасы жоқ."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Телефонда SIM картасы жоқ."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN коды сәйкес келмейді"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Планшет құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін осы планшет бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Телефон құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін осы телефон бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Планшет құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Осы планшет бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Телефон құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Осы телефон бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Планшет құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін пайдаланушы өшіріліп, оның бүкіл деректері жойылады."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Телефон құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін пайдаланушы өшіріліп, оның бүкіл деректері жойылады."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV құрылғысы жақын арада өшеді. Оны қосулы қалдыру үшін басыңыз."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Құрылғы жақын арада өшеді. Оны қосулы қалдыру үшін басыңыз."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Планшет құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Жұмыс профилі өшіріліп, оның бүкіл деректері жойылады."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Телефон құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Жұмыс профилі өшіріліп, оның бүкіл деректері жойылады."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін планшетті есептік жазба арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін телефонды есептік жазба арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-km/strings.xml b/packages/SystemUI/res-product/values-km/strings.xml new file mode 100644 index 000000000000..1c3c7f4cf3cc --- /dev/null +++ b/packages/SystemUI/res-product/values-km/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"គ្មានស៊ីមកាតនៅក្នុងថេប្លេតទេ។"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"គ្មានស៊ីមកាតនៅក្នុងទូរសព្ទទេ។"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"កូដ PIN មិនត្រូវគ្នាទេ"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"អ្នកបានព្យាយាមដោះសោថេប្លេតនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ ប្រសិនបើការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យទេ ថេប្លេតនេះនឹងត្រូវបានកំណត់ឡើងវិញ ហើយវានឹងលុបទិន្នន័យរបស់វាទាំងអស់។"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"អ្នកបានព្យាយាមដោះសោទូរសព្ទនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ ប្រសិនបើការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យទេ ទូរសព្ទនេះនឹងត្រូវបានកំណត់ឡើងវិញ ហើយវានឹងលុបទិន្នន័យរបស់វាទាំងអស់។"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"អ្នកបានព្យាយាមដោះសោថេប្លេតនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង។ ថេប្លេតនេះនឹងត្រូវបានកំណត់ឡើងវិញ ហើយវានឹងលុបទិន្នន័យទាំងអស់របស់វា។"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"អ្នកបានព្យាយាមដោះសោទូរសព្ទនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដងហើយ។ ទូរសព្ទនេះនឹងត្រូវបានកំណត់ឡើងវិញ ហើយវានឹងលុបទិន្នន័យទាំងអស់របស់វា។"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"អ្នកបានព្យាយាមដោះសោថេប្លេតនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ ប្រសិនបើការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យទេ អ្នកប្រើប្រាស់នេះនឹងត្រូវបានលុប ហើយវានឹងលុបទិន្នន័យរបស់អ្នកប្រើប្រាស់ទាំងអស់។"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"អ្នកបានព្យាយាមដោះសោទូរសព្ទនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ ប្រសិនបើការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យទេ អ្នកប្រើប្រាស់នេះនឹងត្រូវបានលុប ហើយវានឹងលុបទិន្នន័យរបស់អ្នកប្រើប្រាស់ទាំងអស់។"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"ឧបករណ៍ Android TV នឹងបិទក្នុងពេលឆាប់ៗនេះ សូមចុចប៊ូតុងដើម្បីបន្តបើកឧបករណ៍។"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ឧបករណ៍នឹងបិទក្នុងពេលឆាប់ៗនេះ សូមចុចដើម្បីបន្តបើកឧបករណ៍។"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"អ្នកបានព្យាយាមដោះសោថេប្លេតនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដងហើយ។ កម្រងព័ត៌មានការងារនេះនឹងត្រូវបានលុប ហើយវានឹងលុបទិន្នន័យកម្រងព័ត៌មានទាំងអស់។"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"អ្នកបានព្យាយាមដោះសោទូរសព្ទនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដងហើយ។ កម្រងព័ត៌មានការងារនេះនឹងត្រូវបានលុប ហើយវានឹងលុបទិន្នន័យកម្រងព័ត៌មានទាំងអស់។"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ ប្រសិនបើការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យទេ អ្នកនឹងត្រូវបានស្នើឲ្យដោះសោថេប្លេតរបស់អ្នក ដោយប្រើគណនីអ៊ីមែល។\n\n សូមព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទីទៀត។"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ ប្រសិនបើការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យទេ អ្នកនឹងត្រូវបានស្នើឲ្យដោះសោទូរសព្ទរបស់អ្នក ដោយប្រើគណនីអ៊ីមែល។\n\n សូមព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទីទៀត។"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-kn/strings.xml b/packages/SystemUI/res-product/values-kn/strings.xml new file mode 100644 index 000000000000..06644f46ea1a --- /dev/null +++ b/packages/SystemUI/res-product/values-kn/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ಟ್ಯಾಬ್ಲೆಟ್ನಲ್ಲಿ ಸಿಮ್ ಕಾರ್ಡ್ ಇಲ್ಲ."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ಪೋನ್ನಲ್ಲಿ ಯಾವುದೇ ಸಿಮ್ ಕಾರ್ಡ್ ಇಲ್ಲ."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ಪಿನ್ ಕೋಡ್ಗಳು ಹೊಂದಾಣಿಕೆಯಾಗುತ್ತಿಲ್ಲ"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಫೋನ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ಫೋನ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಫೋನ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"ಈ Android TV ಸಾಧನವು ಶೀಘ್ರವೇ ಆಫ್ ಆಗುತ್ತದೆ; ಇದನ್ನು ಆನ್ನಲ್ಲಿಡಲು ಬಟನ್ ಅನ್ನು ಒತ್ತಿರಿ."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ಈ ಸಾಧನವು ಶೀಘ್ರವೇ ಆಫ್ ಆಗುತ್ತದೆ; ಇದನ್ನು ಆನ್ನಲ್ಲಿಡಲು ಒತ್ತಿರಿ."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ಫೋನ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಎಳೆದಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಎಳೆದಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ಫೋನ್ ಅನ್ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ko/strings.xml b/packages/SystemUI/res-product/values-ko/strings.xml new file mode 100644 index 000000000000..1d5152e98bca --- /dev/null +++ b/packages/SystemUI/res-product/values-ko/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"태블릿에 SIM 카드가 없습니다."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"휴대전화에 SIM 카드가 없습니다."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 코드가 일치하지 않음"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"태블릿 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 태블릿이 재설정되며 모든 데이터가 삭제됩니다."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 휴대전화가 재설정되며 모든 데이터가 삭제됩니다."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"태블릿 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 태블릿이 재설정되며 모든 데이터가 삭제됩니다."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 휴대전화가 재설정되며 모든 데이터가 삭제됩니다."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"태블릿 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이 사용자와 모든 사용자 데이터가 삭제됩니다."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이 사용자와 모든 사용자 데이터가 삭제됩니다."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV가 곧 꺼집니다. 계속 켜 두려면 버튼을 누르세요."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"기기가 곧 꺼집니다. 계속 켜 두려면 누르세요."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"태블릿 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필과 모든 프로필 데이터가 삭제됩니다."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필과 모든 프로필 데이터가 삭제됩니다."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금 해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금 해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ky/strings.xml b/packages/SystemUI/res-product/values-ky/strings.xml new file mode 100644 index 000000000000..bc4ffa0ea523 --- /dev/null +++ b/packages/SystemUI/res-product/values-ky/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Планшетте SIM-карта жок."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Телефондо SIM-карта жок."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коддор дал келген жок"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Планшеттин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул планшет баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул телефон баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Бул планшет баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет жасадыңыз. Бул телефон баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Планшеттин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV түзмөгү жакында өчүрүлөт, аны күйүк боюнча калтыруу үчүн баскычты басыңыз."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Түзмөк жакында өчүрүлөт, күйүк боюнча калтыруу үчүн басып коюңуз."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили чыгарылып салынып, андагы бардык дайындар жок болот."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили чыгарылып салынып, андагы бардык дайындар жок болот."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Сиз графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин планшетиңизди бөгөттөн электрондук почтаңыз аркылуу чыгарышыңыз талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Сиз графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин телефонуңузду бөгөттөн электрондук почтаңыз аркылуу чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-lo/strings.xml b/packages/SystemUI/res-product/values-lo/strings.xml new file mode 100644 index 000000000000..8d2e0f3d65e7 --- /dev/null +++ b/packages/SystemUI/res-product/values-lo/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ບໍ່ມີຊິມກາດໃນແທັບເລັດ."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ບໍ່ມີ SIM card ໃນໂທລະສັບ."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ລະຫັດ PIN ບໍ່ກົງກັນ"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ຄັ້ງ, ແທັບເລັດນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ຄັ້ງ, ໂທລະສັບນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ແທັບເລັດນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂທລະສັບນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g>ຄັ້ງ, ຜູ້ໃຊ້ນີ້ຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຜູ້ໃຊ້."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ຄັ້ງ, ຜູ້ໃຊ້ນີ້ຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຜູ້ໃຊ້."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"ອຸປະກອນ Android TV ຈະປິດໃນອີກບໍ່ດົນ, ກົດປຸ່ມໃດໜຶ່ງເພື່ອເປີດມັນໄວ້ຕໍ່."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ອຸປະກອນຈະປິດໃນອີກບໍ່ດົນ, ກົດເພື່ອເປີດມັນໄວ້ຕໍ່."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກແທັບເລັດຂອງທ່ານ ດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ອີເມວຂອງທ່ານ.\n\n ກະລຸນາລອງໃໝ່ອີກຄັ້ງໃນອີກ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍບັນຊີອີເມວ.\n\n ລອງໃໝ່ອີກຄັ້ງໃນ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-lt/strings.xml b/packages/SystemUI/res-product/values-lt/strings.xml new file mode 100644 index 000000000000..f29168194f30 --- /dev/null +++ b/packages/SystemUI/res-product/values-lt/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planšetiniame kompiuteryje nėra SIM kortelės."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefone nėra SIM kortelės."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodai nesutampa"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis planšetinis kompiuteris bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Šis planšetinis kompiuteris bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Šis telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"„Android TV“ įrenginys netrukus išsijungs. Paspauskite mygtuką, kad jis liktų įjungtas."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Įrenginys netrukus išsijungs. Paspauskite, kad jis liktų įjungtas."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-lv/strings.xml b/packages/SystemUI/res-product/values-lv/strings.xml new file mode 100644 index 000000000000..6459e257653c --- /dev/null +++ b/packages/SystemUI/res-product/values-lv/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planšetdatorā nav SIM kartes."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Tālrunī nav SIM kartes."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodi neatbilst."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis planšetdators tiks atiestatīts, kā arī visi planšetdatora dati tiks dzēsti."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis tālrunis tiks atiestatīts, kā arī visi tālruņa dati tiks dzēsti."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Šis planšetdators tiks atiestatīts, kā arī visi planšetdatora dati tiks dzēsti."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Šis tālrunis tiks atiestatīts, kā arī visi tālruņa dati tiks dzēsti."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ierīce drīz izslēgsies. Nospiediet pogu, lai tā paliktu ieslēgta."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Ierīce drīz izslēgsies. Nospiediet, lai tā paliktu ieslēgta."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-mk/strings.xml b/packages/SystemUI/res-product/values-mk/strings.xml new file mode 100644 index 000000000000..21fde4d6d815 --- /dev/null +++ b/packages/SystemUI/res-product/values-mk/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Во таблетот нема SIM-картичка."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Во телефонот нема SIM-картичка."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-кодовите не се совпаѓаат"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, таблетот ќе се ресетира, со што ќе се избришат сите негови податоци."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, телефонот ќе се ресетира, со што ќе се избришат сите негови податоци."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER">%d</xliff:g> пати. Овој таблет ќе се ресетира, со што ќе се избришат сите негови податоци."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Овој телефон ќе се ресетира, со што ќе се избришат сите негови податоци."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, корисникот ќе се отстрани, со што ќе се избришат сите негови податоци."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, корисникот ќе се отстрани, со што ќе се избришат сите податоци на корисникот."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Уредот со Android TV наскоро ќе се исклучи, притиснете копче за да остане вклучен."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Уредот наскоро ќе се исклучи, притиснете за да остане вклучен."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите таблетот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите телефонот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ml/strings.xml b/packages/SystemUI/res-product/values-ml/strings.xml new file mode 100644 index 000000000000..c39cce179f47 --- /dev/null +++ b/packages/SystemUI/res-product/values-ml/strings.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ടാബ്ലെറ്റിൽ സിം കാർഡൊന്നുമില്ല."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ഫോണിൽ സിം കാർഡൊന്നുമില്ല."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"പിൻ കോഡുകൾ പൊരുത്തപ്പെടുന്നില്ല"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ടാബ്ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഈ ടാബ്ലെറ്റ് റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ ഈ ഫോൺ റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ടാബ്ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഈ ഫോൺ റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഈ ഫോൺ റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ടാബ്ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ ഈ ഉപയോക്താവിനെ നീക്കം ചെയ്യുകയും, അതുവഴി ഉപയോക്താവിന്റെ എല്ലാ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ ഈ ഉപയോക്താവിനെ നീക്കം ചെയ്യുകയും, അതുവഴി ഉപയോക്താവിന്റെ എല്ലാ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for notification_bubble_title (8330481035191903164) --> + <skip/> + <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android ടിവി ഉടൻ ഓഫാകും, ഓണാക്കി നിർത്താൻ ഒരു ബട്ടൺ അമർത്തുക."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ഉപകരണം ഉടൻ ഓഫാകും, ഓണാക്കി നിർത്താൻ അമർത്തുക."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ടാബ്ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യപ്പെടുകയും, അതുവഴി എല്ലാ പ്രൊഫൈൽ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യപ്പെടുകയും, അതുവഴി എല്ലാ പ്രൊഫൈൽ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ടാബ്ലെറ്റ് അൺലോക്കുചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ശ്രമിക്കുക."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ഫോൺ അൺലോക്കുചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ശ്രമിക്കുക."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-mn/strings.xml b/packages/SystemUI/res-product/values-mn/strings.xml new file mode 100644 index 000000000000..32f3bf9c4633 --- /dev/null +++ b/packages/SystemUI/res-product/values-mn/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Таблетад SIM карт алга."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Утсанд SIM карт алга."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ПИН код тохирохгүй байна"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийлээ. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ таблетыг шинэчлэх бөгөөд бүх өгөгдөл нь устах болно."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийлээ.Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ утсыг шинэчлэх бөгөөд бүх өгөгдөл нь устах болно."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийлээ. Энэ таблетыг шинэчлэх бөгөөд ингэснээр бүх өгөгдөл нь устах болно."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийлээ. Энэ утсыг шинэчлэх бөгөөд ингэснээр бүх өгөгдөл нь устах болно."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийсэн байна. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ хэрэглэгчийг устгах бөгөөд ингэснээр хэрэглэгчийн бүх өгөгдөл устах болно."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийсэн байна. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ хэрэглэгчийг устгах бөгөөд ингэснээр хэрэглэгчийн бүх өгөгдөл устах болно."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Андройд ТВ төхөөрөмж удахгүй унтрах тул асаалттай хэвээр байлгахын тулд товчлуур дээр дарна уу."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Төхөөрөмж удахгүй унтрах тул асаалттай хэвээр байлгахын тулд дарна уу."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Та таблетын түгжээг тайлах оролдогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийсэн байна. Ажлын профайлыг устгах бөгөөд ингэснээр профайлын бүх өгөгдөл устах болно."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийлээ. Ажлын профайлыг устгах бөгөөд ингэснээр профайлын бүх өгөгдлийг устгах болно."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Та түгжээ тайлах загварыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд таблетынхаа түгжээг имэйл бүртгэлээрээ тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Та түгжээ тайлах загварыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд утасныхаа түгжээг имэйл бүртгэлээрээ тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-mr/strings.xml b/packages/SystemUI/res-product/values-mr/strings.xml new file mode 100644 index 000000000000..8ef190e128ef --- /dev/null +++ b/packages/SystemUI/res-product/values-mr/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"टॅबलेटमध्ये सिम कार्ड नाही."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"फोनमध्ये सिम कार्ड नाही."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"पिन कोड जुळत नाहीत"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हे टॅबलेट रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हे टॅबलेट रीसेट केले जाईल, जे त्याचा सर्व डेटा हटवेल."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, या वापरकर्त्याला काढले जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, या वापरकर्त्याला काढले जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV डिव्हाइस लवकरच बंद होणार आहे; सुरू ठेवण्यासाठी बटण दाबा."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"डिव्हाइस लवकरच बंद होणार आहे; सुरू ठेवण्यासाठी स्क्रीनवर किंवा बटण दाबा."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, जे सर्व प्रोफाइल डेटा हटवेल."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, जे सर्व प्रोफाइल डेटा हटवेल."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा टॅब्लेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ms/strings.xml b/packages/SystemUI/res-product/values-ms/strings.xml new file mode 100644 index 000000000000..5443a543ead5 --- /dev/null +++ b/packages/SystemUI/res-product/values-ms/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tiada kad SIM dalam tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Tiada kad SIM dalam telefon."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kod PIN tidak sepadan"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, tablet ini akan ditetapkan semula sekali gus memadamkan semua data."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, telefon ini akan ditetapkan semula sekali gus memadamkan semua data."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Tablet ini akan ditetapkan semula sekali gus memadamkan semua data."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Telefon ini akan ditetapkan semula sekali gus memadamkan semua data."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadamkan semua data pengguna."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadamkan semua data pengguna."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Peranti Android TV akan mati tidak lama lagi; tekan butang untuk memastikan peranti terus hidup."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Peranti akan mati tidak lama lagi; tekan untuk memastikan peranti terus hidup."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadamkan semua data profil."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadamkan semua data profil."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci tablet anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci telefon anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-my/strings.xml b/packages/SystemUI/res-product/values-my/strings.xml new file mode 100644 index 000000000000..3f2891df815c --- /dev/null +++ b/packages/SystemUI/res-product/values-my/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"တက်ဘလက်ထဲတွင် ဆင်းမ်ကဒ် မရှိပါ။"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ဖုန်းထဲတွင် ဆင်းမ်ကဒ် မရှိပါ။"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ပင်နံပါတ် ကိုက်ညီမှုမရှိပါ"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"တက်ဘလက်ကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းခဲ့လျှင် ဤတက်ဘလက်ကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ဖုန်းကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းခဲ့လျှင် ဤဖုန်းကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"တက်ဘလက်ကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ ဤတက်ဘလက်ကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ဖုန်းကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ ဤဖုန်းကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"တက်ဘလက်ကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းခဲ့လျှင် ဤအသုံးပြုသူကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး အသုံးပြုသူဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ဖုန်းကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းသွားလျှင် ဤအသုံးပြုသူကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး အသုံးပြုသူဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV စက်သည် မကြာမီ ပိတ်သွားပါမည်၊ ဆက်ဖွင့်ထားရန် ခလုတ်တစ်ခုနှိပ်ပါ။"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"စက်သည် မကြာမီ ပိတ်သွားပါမည်၊ ဆက်ဖွင့်ထားပါ။"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"တက်ဘလက်ကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ အလုပ်ပရိုဖိုင်ကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး ပရိုဖိုင်ဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ဖုန်းကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ အလုပ်ပရိုဖိုင်ကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး ပရိုဖိုင်ဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ တက်ဘလက်ကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ ဖုန်းကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-nb/strings.xml b/packages/SystemUI/res-product/values-nb/strings.xml new file mode 100644 index 000000000000..6608b25af1d5 --- /dev/null +++ b/packages/SystemUI/res-product/values-nb/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nettbrettet mangler SIM-kort."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonen mangler SIM-kort."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-kodene stemmer ikke overens"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Nettbrettet tilbakestilles etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle dataene på nettbrettet."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Telefonen tilbakestilles etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle dataene på telefonen."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Dette nettbrettet blir tilbakestilt, og alle dataene blir slettet."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Denne telefonen blir tilbakestilt, og alle dataene blir slettet."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Brukeren fjernes etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle brukerdataene."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Brukeren fjernes etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle brukerdataene."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV-enheten slås snart av. Trykk på en knapp for å holde den på."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Enheten slås snart av. Trykk for å holde den på."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Jobbprofilen blir fjernet, og alle profildataene blir slettet."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Jobbprofilen blir fjernet, og alle profildataene blir slettet."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> feil forsøk blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> feil forsøk blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ne/strings.xml b/packages/SystemUI/res-product/values-ne/strings.xml new file mode 100644 index 000000000000..2361ac9b2bac --- /dev/null +++ b/packages/SystemUI/res-product/values-ne/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ट्याब्लेटमा SIM कार्ड छैन।"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"फोनमा SIM कार्ड छैन।"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN कोडहरू मिलेनन्"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यो ट्याब्लेट यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यो फोन यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। यो ट्याब्लेट यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। यो फोन यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यस प्रयोगकर्तालाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यस प्रयोगकर्तालाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV यन्त्र चाँडै निष्क्रिय हुने छ; सक्रिय राख्न कुनै बटन थिच्नुहोस्।"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"यो यन्त्र चाँडै निष्क्रिय हुने छ; सक्रिय राख्न थिच्नुहोस्।"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"तपाईं <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। कार्य प्रोफाइललाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। कार्य प्रोफाइललाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो ट्याब्लेट अनलक गर्न आग्रह गरिनेछ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो फोन अनलक गर्न आग्रह गरिनेछ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-nl/strings.xml b/packages/SystemUI/res-product/values-nl/strings.xml new file mode 100644 index 000000000000..6f71d987fc1a --- /dev/null +++ b/packages/SystemUI/res-product/values-nl/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Geen simkaart in tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Geen simkaart in telefoon."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Pincodes komen niet overeen"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze tablet gereset, waardoor alle gegevens worden verwijderd."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze telefoon gereset, waardoor alle gegevens worden verwijderd."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Deze tablet wordt gereset, waardoor alle gegevens worden verwijderd."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Deze telefoon wordt gereset, waardoor alle gegevens worden verwijderd."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Het Android TV-apparaat wordt binnenkort uitgeschakeld. Druk op een knop om het ingeschakeld te houden."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Het apparaat wordt binnenkort uitgeschakeld. Druk om het ingeschakeld te houden."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-or/strings.xml b/packages/SystemUI/res-product/values-or/strings.xml new file mode 100644 index 000000000000..a6190fcb90c0 --- /dev/null +++ b/packages/SystemUI/res-product/values-or/strings.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ଟାବଲେଟ୍ରେ କୌଣସି SIM କାର୍ଡ ନାହିଁ।"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ଫୋନରେ କୌଣସି SIM କାର୍ଡ ନାହିଁ।"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN କୋଡ୍ ମେଳ ହେଉନାହିଁ"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ଆପଣ ଟାବଲେଟକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଭୁଲ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍ ପ୍ରୟାସ ପରେ, ଏହି ଟାବଲେଟଟି ରିସେଟ୍ ହୋଇଯିବ, ଯାହାଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଲିଟ୍ ହୋଇଯିବ।"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ଆପଣ ଫୋନକୁ ଅନଲକ୍ କରିବାକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଭୁଲ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍ ପ୍ରୟାସ ପରେ, ଏହି ଫୋନଟି ରିସେଟ୍ ହୋଇଯିବ, ଯାହାଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଲିଟ୍ ହୋଇଯିବ।"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ଆପଣ ଟାବଲେଟକୁ ଅନଲକ୍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g> ଥର ଭୁଲ୍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଏହି ଟାବଲେଟକୁ ରିସେଟ୍ କରାଯିବ, ଯାହାଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ଆପଣ ଫୋନଟି ଅନଲକ୍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ୍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଏହି ଫୋନ୍ ରିସେଟ୍ କରାଯିବ, ଯାହା ଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ଆପଣ ଟାବଲେଟ୍ଟିକୁ ଅନଲକ୍ କରିବା ପାଇଁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଚେଷ୍ଟା କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ୍ ପ୍ରୟାସ ପରେ, ୱାର୍କ ପ୍ରୋଫାଇଲ୍କୁ ବାହାର କରିଦିଆଯିବ ଏବଂ ଏହା ଦ୍ୱାରା ସମସ୍ତ ପ୍ରୋଫାଇଲ୍ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ଆପଣ ଫୋନଟି ଅନଲକ୍ କରିବାକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍ ପ୍ରୟାସ ପରେ, ଏହି ୟୁଜରଙ୍କୁ ବାହାର କରିଦିଆଯିବ ଏବଂ ଏହାଦ୍ୱାରା ସମସ୍ତ ୟୁଜର୍ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for notification_bubble_title (8330481035191903164) --> + <skip/> + <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android ଟିଭି ଡିଭାଇସ୍ ଶୀଘ୍ର ବନ୍ଦ ହୋଇଯିବ; ଏହା ଚାଲୁ ରଖିବା ପାଇଁ ଏକ ବଟନ୍ ଦବାନ୍ତୁ।"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ଡିଭାଇସ୍ ଶୀଘ୍ର ବନ୍ଦ ହୋଇଯିବ; ଚାଲୁ ରଖିବା ପାଇଁ ଦବାନ୍ତୁ।"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ଆପଣ ଟାବଲେଟକୁ ଅନଲକ୍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g> ଭୁଲ୍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। କାର୍ଯ୍ୟ ପ୍ରୋଫାଇଲ୍ ବାହାର କରିଦିଆଯିବ, ଯାହାଦ୍ୱାରା ସମସ୍ତ ପ୍ରୋଫାଇଲ୍ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ଆପଣ ଫୋନଟି ଅନଲକ୍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ୍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ୱର୍କ ପ୍ରୋଫାଇଲ୍ ବାହାର କରିଦିଆଯିବ, ଯାହା ଦ୍ୱାରା ସମସ୍ତ ପ୍ରୋଫାଇଲ୍ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ଆପଣଙ୍କ ଅନଲକ୍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଏକ ଇମେଲ୍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ନିଜ ଟାବଲେଟକୁ ଅନଲକ୍ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ଆପଣଙ୍କ ଅନଲକ୍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଏକ ଇମେଲ୍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ନିଜ ଫୋନକୁ ଅନଲକ୍ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-pa/strings.xml b/packages/SystemUI/res-product/values-pa/strings.xml new file mode 100644 index 000000000000..bc16b5ad7a5a --- /dev/null +++ b/packages/SystemUI/res-product/values-pa/strings.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ਟੈਬਲੈੱਟ ਵਿੱਚ ਕੋਈ ਸਿਮ ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ।"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ਫ਼ੋਨ ਵਿੱਚ ਕੋਈ ਸਿਮ ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ।"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ਪਿੰਨ ਕੋਡ ਮੇਲ ਨਹੀਂ ਖਾਂਦੇ"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਹ ਟੈਬਲੈੱਟ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਹ ਫ਼ੋਨ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਇਹ ਟੈਬਲੈੱਟ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਇਹ ਫ਼ੋਨ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਵਰਤੋਂਕਾਰ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਵਰਤੋਂਕਾਰ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for notification_bubble_title (8330481035191903164) --> + <skip/> + <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ਡੀਵਾਈਸ ਜਲਦ ਹੀ ਬੰਦ ਹੋ ਜਾਵੇਗਾ; ਇਸਨੂੰ ਚਾਲੂ ਰੱਖਣ ਲਈ ਕੋਈ ਬਟਨ ਦਬਾਓ।"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ਡੀਵਾਈਸ ਜਲਦ ਹੀ ਬੰਦ ਹੋ ਜਾਵੇਗਾ, ਇਸਨੂੰ ਚਾਲੂ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਉਲੀਕਿਆ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣੇ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਵੇਗਾ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-pl/strings.xml b/packages/SystemUI/res-product/values-pl/strings.xml new file mode 100644 index 000000000000..9ba9b6521e3c --- /dev/null +++ b/packages/SystemUI/res-product/values-pl/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Brak karty SIM w tablecie."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Brak karty SIM w telefonie."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kody PIN nie pasują"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach tablet zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach telefon zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Tablet zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Telefon zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich danych użytkownika."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich danych użytkownika."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Urządzenie z Androidem TV za chwilę się wyłączy. Naciśnij przycisk, by pozostało włączone."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Urządzenie za chwilę się wyłączy. Naciśnij, by pozostało włączone."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Profil służbowy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Profil służbowy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-pt-rBR/strings.xml b/packages/SystemUI/res-product/values-pt-rBR/strings.xml new file mode 100644 index 000000000000..73a0983f54b6 --- /dev/null +++ b/packages/SystemUI/res-product/values-pt-rBR/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Não há um chip no tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Não há um chip no smartphone."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN não coincidem"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será redefinido, o que excluirá todos os dados dele."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este smartphone será redefinido, o que excluirá todos os dados dele."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"O dispositivo Android TV entrará no modo de espera em breve. Pressione um botão para mantê-lo ativado."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"O dispositivo entrará no modo de espera em breve. Pressione para mantê-lo ativado."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-pt-rPT/strings.xml b/packages/SystemUI/res-product/values-pt-rPT/strings.xml new file mode 100644 index 000000000000..e324686e026f --- /dev/null +++ b/packages/SystemUI/res-product/values-pt-rPT/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nenhum cartão SIM no tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nenhum cartão SIM no telemóvel."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN não coincidem"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este tablet será reposto, o que eliminará todos os dados do mesmo."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este telemóvel será reposto, o que eliminará todos os dados do mesmo."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será reposto, o que eliminará todos os dados do mesmo."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. Este telemóvel será reposto, o que eliminará todos os dados do mesmo."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados do mesmo."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados do mesmo."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"O dispositivo Android TV irá desligar-se brevemente. Prima um botão para o manter ligado."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"O dispositivo irá desligar-se brevemente. Prima para o manter ligado."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do mesmo."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do mesmo."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-pt/strings.xml b/packages/SystemUI/res-product/values-pt/strings.xml new file mode 100644 index 000000000000..73a0983f54b6 --- /dev/null +++ b/packages/SystemUI/res-product/values-pt/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Não há um chip no tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Não há um chip no smartphone."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN não coincidem"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será redefinido, o que excluirá todos os dados dele."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este smartphone será redefinido, o que excluirá todos os dados dele."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"O dispositivo Android TV entrará no modo de espera em breve. Pressione um botão para mantê-lo ativado."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"O dispositivo entrará no modo de espera em breve. Pressione para mantê-lo ativado."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ro/strings.xml b/packages/SystemUI/res-product/values-ro/strings.xml new file mode 100644 index 000000000000..536d7d923858 --- /dev/null +++ b/packages/SystemUI/res-product/values-ro/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nu există card SIM în tabletă."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nu există card SIM în telefon."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Codurile PIN nu coincid"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, această tabletă va fi resetată, iar toate datele acesteia vor fi șterse."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Această tabletă va fi resetată, iar toate datele acesteia vor fi șterse."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Dispozitivul Android TV se va opri în curând. Apăsați un buton pentru a-l menține pornit."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Dispozitivul se va opri în curând. Apăsați pentru a-l menține pornit."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ru/strings.xml b/packages/SystemUI/res-product/values-ru/strings.xml new file mode 100644 index 000000000000..a8707747cb92 --- /dev/null +++ b/packages/SystemUI/res-product/values-ru/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Нет SIM-карты."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Нет SIM-карты."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коды не совпадают."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Вы пытались разблокировать планшет несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи произойдет сброс настроек и все данные на устройстве будут удалены."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Вы пытались разблокировать телефон несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи произойдет сброс настроек и все данные на устройстве будут удалены."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Достигнуто максимальное количество неудачных попыток разблокировать планшет (<xliff:g id="NUMBER">%d</xliff:g>). Настройки устройства будут сброшены, а все его данные – удалены."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Настройки устройства будут сброшены, а все его данные – удалены."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Вы пытались разблокировать планшет несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи профиль пользователя и все его данные будут удалены."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Вы пытались разблокировать телефон несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи профиль пользователя и все его данные будут удалены."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Устройство Android TV скоро выключится. Чтобы этого не произошло, нажмите любую кнопку."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Устройство скоро выключится. Чтобы этого не произошло, нажмите любую кнопку или коснитесь экрана."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Достигнуто максимальное количество неудачных попыток разблокировать планшет (<xliff:g id="NUMBER">%d</xliff:g>). Рабочий профиль и все его данные будут удалены."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Рабочий профиль и все его данные будут удалены."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Вы ввели неверный графический ключ несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать планшет с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Вы ввели неверный графический ключ несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать телефон с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-si/strings.xml b/packages/SystemUI/res-product/values-si/strings.xml new file mode 100644 index 000000000000..2d02d1f66370 --- /dev/null +++ b/packages/SystemUI/res-product/values-si/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ටැබ්ලටයේ SIM පත නොමැත."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"දුරකථනය තුල SIM පතක් නැත."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN කේත නොගැළපේ."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම ටැබ්ලට් පරිගණකය යළි සකසනු ඇති අතර, එය එහි සියලු දත්ත මකනු ඇත."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම දුරකථනය යළි සකසනු ඇති අතර, එය එහි සියලු දත්ත මකනු ඇත."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. මෙම ටැබ්ලට් පරිගණකය යළි සකසනු ඇති අතර, එය එහි සියලු පදත්ත මකනු ඇත."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. මෙම දුරකථනය යළි සකසනු ඇති අතර, එය එහි සියලු පදත්ත මකනු ඇත."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම පරිශීලකයා ඉවත් කරනු ඇති අතර, එය සියලු පරිශීලක දත්ත මකනු ඇත."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම පරිශීලකයා ඉවත් කරනු ඇති අතර, එය සියලු පරිශීලක දත්ත මකනු ඇත."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV උපාංගය ඉක්මනින් ක්රියා විරහිත වනු ඇත; එය දිගටම ක්රියාත්මක කර තැබීමට බොත්තමක් ඔබන්න."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"උපාංගය ඉක්මනින් ක්රියා විරහිත වනු ඇත; එය දිගටම ක්රියාත්මක කර තැබීමට ඔබන්න."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. කාර්යාල පැතිකඩ ඉවත් කරනු ඇති අතර, එය සියලු පැතිකඩ දත්ත මකනු ඇත."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. කාර්යාල පැතිකඩ ඉවත් කරනු ඇති අතර, එය සියලු පැතිකඩ දත්ත මකනු ඇත."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ඔබ අගුළු ඇරිමේ රටාව <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් වැරදියට ඇඳ ඇත. තවත් අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%2$d</xliff:g> කින් පසුව, ඊ-තැපැල් ගිණුම භාවිතා කරමින් ඔබගේ ටැබ්ලටයේ අගුළු ඇරීමට ඔබට පවසනු ඇත.\n\n නැවත තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> කින් උත්සාහ කරන්න."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%2$d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-sk/strings.xml b/packages/SystemUI/res-product/values-sk/strings.xml new file mode 100644 index 000000000000..b57ecf9d77a9 --- /dev/null +++ b/packages/SystemUI/res-product/values-sk/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"V tablete nie je žiadna SIM karta."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"V telefóne nie je žiadna SIM karta."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kódy PIN sa nezhodujú"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento tablet obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento telefón obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tablet ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Tablet bude obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Telefón bude obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento používateľ odstránený a spolu s ním všetky jeho údaje."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento používateľ odstránený a spolu s ním všetky jeho údaje."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Zariadenie Android TV sa čoskoro vypne. Ak ho chcete ponechať zapnuté, stlačte ľubovoľné tlačidlo."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Zariadenie sa čoskoro vypne. Ak ho chcete ponechať zapnuté, stlačte ľubovoľné tlačidlo."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tablet ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Už ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%2$d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Už ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g>} s."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-sl/strings.xml b/packages/SystemUI/res-product/values-sl/strings.xml new file mode 100644 index 000000000000..99cb111dc8c3 --- /dev/null +++ b/packages/SystemUI/res-product/values-sl/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"V tabličnem računalniku ni kartice SIM."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"V telefonu ni kartice SIM."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kodi PIN se ne ujemata"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ponastavljen in vsi podatki v njem bodo izbrisani."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ponastavljen in vsi podatki v njem bodo izbrisani."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat, zato bo ponastavljen, vsi podatki v njem pa bodo izbrisani."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat, zato bo ponastavljen, vsi podatki v njem pa bodo izbrisani."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ta uporabnik odstranjen in vsi podatki uporabnika bodo izbrisani."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ta uporabnik odstranjen in vsi podatki uporabnika bodo izbrisani."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Naprava Android TV se bo kmalu izklopila. Če tega ne želite, pritisnite poljuben gumb."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Naprava se bo kmalu izklopila. Če tega ne želite, pritisnite poljuben gumb."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen in vsi podatki profila bodo izbrisani."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen in vsi podatki profila bodo izbrisani."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\n Poskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da telefon odklenete z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-sq/strings.xml b/packages/SystemUI/res-product/values-sq/strings.xml new file mode 100644 index 000000000000..723c4757e71f --- /dev/null +++ b/packages/SystemUI/res-product/values-sq/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nuk ka kartë SIM në tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Në telefon nuk ka kartë SIM."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kodet PIN nuk përputhen"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht për ta shkyçur tabletin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> përpjekjeve të tjera të pasuksesshme, tableti do të rivendoset, gjë që do të rivendosë të gjitha të dhënat e tij."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> përpjekjeve të tjera të pasuksesshme, telefoni do të rivendoset, gjë që do të fshijë të gjitha të dhënat e tij."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Ky tablet do të rivendoset, gjë që do të fshijë të gjitha të dhënat e tij."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Ky telefon do të rivendoset, gjë që do të fshijë të gjitha të dhënat e tij."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, përdoruesi do të hiqet dhe të gjitha të dhënat e përdoruesit në të, do të fshihen."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, përdoruesi do të hiqet dhe të gjitha të dhënat e përdoruesit në të, do të fshihen."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Pajisja Android TV do të fiket së shpejti. Shtyp një buton për ta mbajtur të ndezur."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Pajisja do të fiket së shpejti. Shtype për ta mbajtur të ndezur."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Profili i punës do të hiqet, gjë që do të fshijë të gjitha të dhënat e profilit."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Profili i punës do të hiqet, gjë që do të fshijë të gjitha të dhënat e profilit."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd të shkyçjes. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh tabletin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd të shkyçjes. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh telefonin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-sr/strings.xml b/packages/SystemUI/res-product/values-sr/strings.xml new file mode 100644 index 000000000000..0e6106e9d1ee --- /dev/null +++ b/packages/SystemUI/res-product/values-sr/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"У таблету нема SIM картице."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"У телефону нема SIM картице."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN кодови се не подударају"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, овај таблет ће се ресетовати, чиме се бришу сви подаци корисника."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, овај телефон ће се ресетовати, чиме се бришу сви подаци корисника."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Овај таблет ће се ресетовати, чиме се бришу сви подаци."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Овај телефон ће се ресетовати, чиме се бришу сви подаци."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо овог корисника, чиме се бришу сви подаци корисника."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо овог корисника, чиме се бришу сви подаци корисника."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ће се ускоро искључити. Притисните дугме да би остао укључен."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Уређај ће се ускоро искључити. Притисните да би остао укључен."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо профил за Work, чиме се бришу сви подаци са профила."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо профил за Work, чиме се бришу сви подаци са профила."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате таблет помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате телефон помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-sv/strings.xml b/packages/SystemUI/res-product/values-sv/strings.xml new file mode 100644 index 000000000000..05de9eb5d4a7 --- /dev/null +++ b/packages/SystemUI/res-product/values-sv/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Inget SIM-kort i surfplattan."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Inget SIM-kort i mobilen."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Pinkoderna stämmer inte överens"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök återställs surfplattan och all data raderas."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök återställs mobilen och all data raderas."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Surfplattan återställs och all data raderas."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Mobilen återställs och all data raderas."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök tas användaren bort och all användardata raderas."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök tas användaren bort och all användardata raderas."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV-enheten stängs snart av. Tryck på en knapp för att behålla den på."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Enheten stängs snart av. Tryck för att behålla den på."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp surfplattan med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-sw/strings.xml b/packages/SystemUI/res-product/values-sw/strings.xml new file mode 100644 index 000000000000..09eb0b2b34b2 --- /dev/null +++ b/packages/SystemUI/res-product/values-sw/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Hakuna SIM kadi katika kompyuta kibao."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Hakuna SIM kadi kwenye simu."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Nambari za PIN hazifanani"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Umejaribu kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, kompyuta hii kibao itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Umejaribu kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, simu hii itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Kompyuta hii kibao itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Simu hii itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Umejaribu kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, mtumiaji huyu ataondolewa, hatua itakayofuta data yake yote."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Umejaribu kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, mtumiaji huyu ataondolewa, hatua itakayofuta data yake yote."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Kifaa cha Android TV kitazima hivi karibuni; bonyeza kitufe ili kisizime."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Kifaa kitazima hivi karibuni; bonyeza ili kisizime."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Umejaribu kufungua kompyuta kibao mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa kufungua kompyuta yako kibao kwa kutumia akaunti yako ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ta/strings.xml b/packages/SystemUI/res-product/values-ta/strings.xml new file mode 100644 index 000000000000..35e3f8255e93 --- /dev/null +++ b/packages/SystemUI/res-product/values-ta/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"டேப்லெட்டில் சிம் கார்டு இல்லை."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"மொபைலில் சிம் கார்டு இல்லை."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"பின் குறியீடுகள் பொருந்தவில்லை"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்த டேப்லெட் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"மொபைலைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்த மொபைல் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இந்த டேப்லெட் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இந்த மொபைல் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்தப் பயனர் அகற்றப்பட்டு, எல்லாப் பயனர் தரவும் நீக்கப்படும்."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"மொபைலைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்தப் பயனர் அகற்றப்பட்டு, எல்லாப் பயனர் தரவும் நீக்கப்படும்."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV விரைவில் ஆஃப் ஆகலாம். இதைத் தொடர்ந்து ஆனில் வைக்க ஒரு பட்டனைத் தட்டவும்."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"இந்தச் சாதனம் விரைவில் ஆஃப் ஆகலாம், இதைத் தொடர்ந்து ஆனில் வைக்கத் தட்டவும்."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். பணிக் கணக்கு அகற்றப்பட்டு, எல்லாச் சுயவிவரத் தரவும் நீக்கப்படும்."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். பணிக் கணக்கு அகற்றப்பட்டு, எல்லாச் சுயவிவரத் தரவும் நீக்கப்படும்."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"திறப்பதற்கான பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி டேப்லெட்டைத் திறக்கும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"திறப்பதற்கான பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி மொபைலைத் திறக்கும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-te/strings.xml b/packages/SystemUI/res-product/values-te/strings.xml new file mode 100644 index 000000000000..6f172eee730f --- /dev/null +++ b/packages/SystemUI/res-product/values-te/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"టాబ్లెట్లో SIM కార్డ్ లేదు."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ఫోన్లో SIM కార్డ్ లేదు."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"పిన్ కోడ్లు సరిపోలలేదు"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ టాబ్లెట్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ ఫోన్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. ఈ టాబ్లెట్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. ఈ ఫోన్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ వినియోగదారు తీసివేయబడతారు, తద్వారా వినియోగదారు డేటా మొత్తం తొలగించబడుతుంది."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"మీరు ఫోన్ని అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ వినియోగదారు తీసివేయబడతారు, తద్వారా వినియోగదారు డేటా మొత్తం తొలగించబడుతుంది."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV పరికరం త్వరలో ఆఫ్ అయిపోతుంది; దాన్ని ఆన్లో ఉంచడానికి బటన్ను నొక్కండి."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"పరికరం త్వరలో ఆఫ్ అయిపోతుంది; దీన్ని ఆన్లో ఉంచడానికి నొక్కండి."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, తద్వారా ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"మీరు ఫోన్ని అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, తద్వారా ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీరు ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్ను అన్లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీరు ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్ను అన్లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-th/strings.xml b/packages/SystemUI/res-product/values-th/strings.xml new file mode 100644 index 000000000000..8c9e72a8fffd --- /dev/null +++ b/packages/SystemUI/res-product/values-th/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ไม่มีซิมการ์ดในแท็บเล็ต"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ไม่มีซิมการ์ดในโทรศัพท์"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"รหัส PIN ไม่ตรง"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะรีเซ็ตแท็บเล็ตเครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะรีเซ็ตโทรศัพท์เครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตแท็บเล็ตเครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตโทรศัพท์เครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลทั้งหมดของผู้ใช้"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลทั้งหมดของผู้ใช้"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"อุปกรณ์ Android TV จะปิดเครื่องในอีกไม่ช้า กดปุ่มเพื่อเปิดอุปกรณ์ต่อไป"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"อุปกรณ์จะปิดเครื่องในอีกไม่ช้า กดเพื่อเปิดอุปกรณ์ต่อไป"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-tl/strings.xml b/packages/SystemUI/res-product/values-tl/strings.xml new file mode 100644 index 000000000000..d3901ee29d7a --- /dev/null +++ b/packages/SystemUI/res-product/values-tl/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Walang SIM card sa tablet."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Walang SIM card sa telepono."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Hindi nagtutugma ang mga PIN code"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, ire-reset ang tablet na ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, ire-reset ang teleponong ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Ire-reset ang tablet na ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Ire-reset ang teleponong ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Mao-off na ang Android TV device; pumindot ng button para panatilihin itong naka-on."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Mao-off na ang device; pumindot para panatilihin itong naka-on."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-tr/strings.xml b/packages/SystemUI/res-product/values-tr/strings.xml new file mode 100644 index 000000000000..d6e0c39ee24b --- /dev/null +++ b/packages/SystemUI/res-product/values-tr/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tablette SIM kart yok."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonda SIM kart yok."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodları eşleşmiyor"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tabletin kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu tablet sıfırlanacak ve tüm verileri silinecektir."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefonun kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu telefon sıfırlanacak ve tüm verileri silinecektir."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tabletin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu tablet sıfırlanacak ve tüm verileri silinecektir."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu telefon sıfırlanacak ve tüm verileri silinecektir."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tabletin kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefonun kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV cihazı kısa süre içinde kapanacak. Cihazınızı açık tutmak için bir düğmeye basın."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Cihaz kısa süre içinde kapanacak. Cihazı açık tutmak için düğmeye basın."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tabletin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> defa yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız denemeden sonra, tabletinizin kilidini bir e-posta hesabı kullanarak açmanız istenir.\n<xliff:g id="NUMBER_2">%3$d</xliff:g>\n saniye içinde tekrar deneyin."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız denemeden sonra telefonunuzun kilidini bir e-posta hesabı kullanarak açmanız istenir.\n<xliff:g id="NUMBER_2">%3$d</xliff:g>\n saniye içinde tekrar deneyin."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-uk/strings.xml b/packages/SystemUI/res-product/values-uk/strings.xml new file mode 100644 index 000000000000..a53043c621bc --- /dev/null +++ b/packages/SystemUI/res-product/values-uk/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"У пристрої немає SIM-карти."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"У телефоні немає SIM-карти."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коди не збігаються"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде скинуто налаштування планшета й видалено всі його дані."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде скинуто налаштування телефона й видалено всі його дані."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER">%d</xliff:g>. Буде скинуто налаштування цього планшета й видалено всі його дані."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде скинуто налаштування цього телефона й видалено всі його дані."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде видалено цього користувача й усі його дані."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде видалено цього користувача й усі його дані."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Незабаром пристрій Android TV буде вимкнено. Натисніть кнопку, щоб цього не сталося."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Незабаром пристрій буде вимкнено. Натисніть, щоб цього не сталося."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з’явиться запит розблокувати планшет за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-ur/strings.xml b/packages/SystemUI/res-product/values-ur/strings.xml new file mode 100644 index 000000000000..4569ee3a2967 --- /dev/null +++ b/packages/SystemUI/res-product/values-ur/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ٹیبلیٹ میں کوئی SIM کارڈ نہیں ہے۔"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"فون میں کوئی SIM کارڈ نہيں ہے۔"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN کوڈز مماثل نہیں ہیں"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس ٹیبلیٹ کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس فون کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ اس ٹیبلیٹ کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ اس فون کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV آلہ جلد ہی بند ہوجائے گا آن رکھنے کے ليے بٹن دبائیں۔"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"آلہ جلد ہی بند ہوجائے گا اسے آن رکھنے کے ليے دبائیں۔"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا ٹیبلیٹ غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-uz/strings.xml b/packages/SystemUI/res-product/values-uz/strings.xml new file mode 100644 index 000000000000..105ae9dd08e7 --- /dev/null +++ b/packages/SystemUI/res-product/values-uz/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planshetingizda SIM karta yo‘q."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefoningizda SIM karta yo‘q."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kod mos kelmadi"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu planshetda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu telefonda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu planshetda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu telefonda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV qurilmasi oʻchish arafasida, yoniq qolishi uchun istalgan tugmani bosing."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Qurilma oʻchish arafasida, yoniq qolishi uchun istalgan tugmani bosing."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ishchi profil o‘chirib tashlanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ishchi profil o‘chirib tashlanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin, sizdan e-pochtangizdan foydalanib, planshet qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin yana urinib ko‘ring."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin qayta urinib ko‘ring."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-vi/strings.xml b/packages/SystemUI/res-product/values-vi/strings.xml new file mode 100644 index 000000000000..c9022eea2af2 --- /dev/null +++ b/packages/SystemUI/res-product/values-vi/strings.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Không có thẻ SIM nào trong máy tính bảng."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Không có thẻ SIM nào trong điện thoại."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Mã PIN không khớp"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, máy tính bảng này sẽ được đặt lại, tức là tất cả dữ liệu của máy tính bảng sẽ bị xóa."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, điện thoại này sẽ được đặt lại, tức là tất cả dữ liệu của điện thoại sẽ bị xóa."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER">%d</xliff:g> lần. Máy tính bảng này sẽ được đặt lại, tức là tất cả dữ liệu của máy tính bảng sẽ bị xóa."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Điện thoại này sẽ được đặt lại, tức là tất cả dữ liệu của điện thoại sẽ bị xóa."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for notification_bubble_title (8330481035191903164) --> + <skip/> + <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Thiết bị Android TV sẽ sớm tắt. Hãy nhấn vào một nút để thiết bị vẫn bật."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Thiết bị sẽ sớm tắt. Hãy nhấn vào một nút để thiết bị vẫn bật."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string> +</resources> diff --git a/packages/SystemUI/res-product/values-zh-rCN/strings.xml b/packages/SystemUI/res-product/values-zh-rCN/strings.xml new file mode 100644 index 000000000000..7109c9990bee --- /dev/null +++ b/packages/SystemUI/res-product/values-zh-rCN/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"平板电脑中没有 SIM 卡。"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"手机中没有 SIM 卡。"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 码不匹配"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,平板电脑将会被重置,而这将删除其中的所有数据。"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,手机将会被重置,而这将删除其中的所有数据。"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。这部平板电脑将会被重置,而这将删除其中的所有数据。"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。这部手机将会被重置,而这将删除其中的所有数据。"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统将移除此用户,而这将删除所有的用户数据。"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统将移除此用户,而这将删除所有的用户数据。"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV 设备即将关闭;按一下相应的按钮即可让设备保持开启状态。"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"设备即将关闭;按一下即可让设备保持开启状态。"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-zh-rHK/strings.xml b/packages/SystemUI/res-product/values-zh-rHK/strings.xml new file mode 100644 index 000000000000..233b2454ea7a --- /dev/null +++ b/packages/SystemUI/res-product/values-zh-rHK/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"平板電腦中沒有 SIM 卡。"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"手機中沒有 SIM 卡。"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 碼不符"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將重設此平板電腦,而平板電腦的所有資料亦會一併刪除。"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將重設此手機,而手機的所有資料亦會一併刪除。"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將重設此平板電腦,而平板電腦的所有資料亦會一併刪除。"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將重設此手機,而手機的所有資料亦會一併刪除。"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將移除此使用者,而所有使用者資料亦會一併刪除。"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將移除此使用者,而所有使用者資料亦會一併刪除。"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV 裝置即將關閉,按下按鈕即可保持開啟。"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"裝置即將關閉,輕按即可保持開啟。"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-zh-rTW/strings.xml b/packages/SystemUI/res-product/values-zh-rTW/strings.xml new file mode 100644 index 000000000000..87e7dc430ed9 --- /dev/null +++ b/packages/SystemUI/res-product/values-zh-rTW/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"平板電腦中沒有 SIM 卡。"</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"手機中沒有 SIM 卡。"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 碼不符"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會重設這台平板電腦,其中的所有資料也會一併遭到刪除。"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會重設這支手機,其中的所有資料也會一併遭到刪除。"</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統會重設這台平板電腦,其中的所有資料也會一併遭到刪除。"</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統會重設這支手機,其中的所有資料也會一併遭到刪除。"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,這位使用者將遭到移除,所有相關的使用者資料也會一併遭到刪除。"</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,這位使用者將遭到移除,所有相關的使用者資料也會一併遭到刪除。"</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV 裝置即將進入待機模式。如要讓裝置保持開啟狀態,請按下任一按鈕。"</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"裝置即將進入待機模式。如要讓裝置保持開啟狀態,請輕觸螢幕或按下按鈕。"</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。你的工作資料夾將遭到移除,所有設定檔資料也會一併遭到刪除。"</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。你的工作資料夾將遭到移除,所有設定檔資料也會一併遭到刪除。"</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統就會要求你透過電子郵件帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統就會要求你透過電子郵件帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string> +</resources> diff --git a/packages/SystemUI/res-product/values-zu/strings.xml b/packages/SystemUI/res-product/values-zu/strings.xml new file mode 100644 index 000000000000..2c8728b6370a --- /dev/null +++ b/packages/SystemUI/res-product/values-zu/strings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- +/** + * Copyright (c) 2009, 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. + */ + --> +<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for global_action_screenshot (2760267567509131654) --> + <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Alikho ikhadi le-SIM efonini."</string> + <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Alikho ikhadi le-SIM efonini."</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Iphinikhodi ayifani"</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, le thebulethi izosethwa kabusha, okuzosusa yonke idatha yayo."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, le foni izosethwa kabusha, okuzosusa yonke idatha yayo."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Le thebulethi izosethwa kabusha, okuzosusa yonke idatha yayo."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Le foni izosethwa kabusha, okuzosusa yonke idatha yayo."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string> + <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string> + <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) --> + <skip/> + <!-- no translation found for cancel (1089011503403416730) --> + <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) --> + <skip/> + <!-- no translation found for accessibility_casting (8708751252897282313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) --> + <skip/> + <!-- no translation found for accessibility_work_mode (1280025758672376313) --> + <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) --> + <skip/> + <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) --> + <skip/> + <!-- no translation found for dock_alignment_not_charging (1002617659995575624) --> + <skip/> + <!-- no translation found for reset (8715144064608810383) --> + <skip/> + <!-- no translation found for notification_channel_alerts (3385787053375150046) --> + <skip/> + <!-- no translation found for app_info (5153758994129963243) --> + <skip/> + <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Idivayisi ye-Android TV maduze izovalwa, cindezela inkinobho ukuze uyigcine ivuliwe."</string> + <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Idivayisi maduze izovalwa, cindezela ukuze uyigcine ivuliwe."</string> +<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string> + <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Udwebe ngokungalungile iphethini yakho yokuvula ngezikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphumelelanga kaningi engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuthi uvule ithebulethi yakho usebenzisa i-akhawunti ye-imeyili.\n\nZama futhi kumasekhondi angu-<xliff:g id="NUMBER_2">%3$d</xliff:g>."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%1$d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%3$d</xliff:g> imizuzwana."</string> +</resources> diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml new file mode 100644 index 000000000000..54e5d4178d7a --- /dev/null +++ b/packages/SystemUI/res-product/values/strings.xml @@ -0,0 +1,125 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2009, 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. + */ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Indication when device is slow charging due to misalignment on the dock. [CHAR LIMIT=60] --> + <string name="dock_alignment_slow_charging" product="default">Realign phone for faster charging</string> + + <!-- Indication when device is not charging due to bad placement on the dock. [CHAR LIMIT=60] --> + <string name="dock_alignment_not_charging" product="default">Realign phone to charge wirelessly</string> + + <!-- Message of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=NONE] --> + <string name="inattentive_sleep_warning_message" product="tv">The Android TV device will soon turn off; press a button to keep it on.</string> + <!-- Message of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=NONE] --> + <string name="inattentive_sleep_warning_message" product="default">The device will soon turn off; press to keep it on.</string> + + <!-- Shown when there is no SIM card. --> + <string name="keyguard_missing_sim_message" product="tablet">No SIM card in tablet.</string> + <!-- Shown when there is no SIM card. --> + <string name="keyguard_missing_sim_message" product="default">No SIM card in phone.</string> + + <!-- String shown in PUK screen when PIN codes don't match --> + <string name="kg_invalid_confirm_pin_hint" product="default">PIN codes does not match</string> + + <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. [CHAR LIMIT=none] --> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet"> + You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times. + After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, + this tablet will be reset, which will delete all its data. + </string> + <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. [CHAR LIMIT=none] --> + <string name="kg_failed_attempts_almost_at_wipe" product="default"> + You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times. + After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, + this phone will be reset, which will delete all its data. + </string> + <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped [CHAR LIMIT=none] --> + <string name="kg_failed_attempts_now_wiping" product="tablet"> + You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times. + This tablet will be reset, which will delete all its data. + </string> + <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped [CHAR LIMIT=none] --> + <string name="kg_failed_attempts_now_wiping" product="default"> + You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times. + This phone will be reset, which will delete all its data. + </string> + + <!-- Message shown when user is almost at the limit of password attempts where the user will be removed. [CHAR LIMIT=none] --> + <string name="kg_failed_attempts_almost_at_erase_user" product="tablet"> + You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times. + After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, + this user will be removed, which will delete all user data. + </string> + <!-- Message shown when user is almost at the limit of password attempts where the user will be removed. [CHAR LIMIT=none] --> + <string name="kg_failed_attempts_almost_at_erase_user" product="default"> + You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times. + After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, + this user will be removed, which will delete all user data. + </string> + <!-- Message shown in dialog when user has exceeded the maximum attempts and the user will be removed. [CHAR LIMIT=none] --> + <string name="kg_failed_attempts_now_erasing_user" product="tablet"> + You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times. + This user will be removed, which will delete all user data. + </string> + <!-- Message shown in dialog when user has exceeded the maximum attempts and the user will be removed. [CHAR LIMIT=none] --> + <string name="kg_failed_attempts_now_erasing_user" product="default"> + You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times. + This user will be removed, which will delete all user data. + </string> + + <!-- Message shown when user is almost at the limit of password attempts where the profile will be removed. [CHAR LIMIT=none] --> + <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet"> + You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times. + After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, + the work profile will be removed, which will delete all profile data. + </string> + <!-- Message shown when user is almost at the limit of password attempts where the profile will be removed. [CHAR LIMIT=none] --> + <string name="kg_failed_attempts_almost_at_erase_profile" product="default"> + You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times. + After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, + the work profile will be removed, which will delete all profile data. + </string> + <!-- Message shown in dialog when user has exceeded the maximum attempts and the profile will be removed. [CHAR LIMIT=none] --> + <string name="kg_failed_attempts_now_erasing_profile" product="tablet"> + You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times. + The work profile will be removed, which will delete all profile data. + </string> + <!-- Message shown in dialog when user has exceeded the maximum attempts and the profile will be removed. [CHAR LIMIT=none] --> + <string name="kg_failed_attempts_now_erasing_profile" product="default"> + You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times. + The work profile will be removed, which will delete all profile data. + </string> + + <!-- Message shown in dialog when user is almost at the limit where they will be + locked out and may have to enter an alternate username/password to unlock the phone --> + <string name="kg_failed_attempts_almost_at_login" product="tablet"> + You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times. + After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, + you will be asked to unlock your tablet using an email account.\n\n + Try again in <xliff:g id="number">%3$d</xliff:g> seconds. + </string> + <!-- Message shown in dialog when user is almost at the limit where they will be + locked out and may have to enter an alternate username/password to unlock the phone --> + <string name="kg_failed_attempts_almost_at_login" product="default"> + You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times. + After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts, + you will be asked to unlock your phone using an email account.\n\n + Try again in <xliff:g id="number">%3$d</xliff:g> seconds. + </string> + +</resources> diff --git a/packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.png b/packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.png Binary files differdeleted file mode 100644 index 135dabb63069..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable/tv_bg_item_app_info.xml b/packages/SystemUI/res/drawable/tv_circle_dark.xml index 1bbb8c3e8ef0..d1ba8e71ec31 100644 --- a/packages/SystemUI/res/drawable/tv_bg_item_app_info.xml +++ b/packages/SystemUI/res/drawable/tv_circle_dark.xml @@ -16,7 +16,9 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - <corners android:radius="24dp"/> - <solid android:color="@color/tv_audio_recording_bar_chip_background"/> -</shape> + android:shape="oval"> + + <solid + android:color="@color/tv_audio_recording_indicator_background" /> + +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/circle_red.xml b/packages/SystemUI/res/drawable/tv_circle_white_translucent.xml index fd3c125e5ab8..55d21de00ca3 100644 --- a/packages/SystemUI/res/drawable/circle_red.xml +++ b/packages/SystemUI/res/drawable/tv_circle_white_translucent.xml @@ -16,6 +16,9 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="oval"> - <solid android:color="@color/red"/> + android:shape="oval"> + + <solid + android:color="@color/tv_audio_recording_indicator_pulse" /> + </shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/tv_ic_mic_white.xml b/packages/SystemUI/res/drawable/tv_ic_mic_white.xml index 1bea8a19c8b9..d887113c7717 100644 --- a/packages/SystemUI/res/drawable/tv_ic_mic_white.xml +++ b/packages/SystemUI/res/drawable/tv_ic_mic_white.xml @@ -1,25 +1,27 @@ -<?xml version="1.0" encoding="utf-8"?> <!-- - ~ Copyright (C) 2019 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> +Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:viewportWidth="44" - android:viewportHeight="44" - android:width="44dp" - android:height="44dp"> - <path - android:pathData="M22 25.6666667C25.0433333 25.6666667 27.4816667 23.21 27.4816667 20.1666667L27.5 9.16666667C27.5 6.12333333 25.0433333 3.66666667 22 3.66666667C18.9566667 3.66666667 16.5 6.12333333 16.5 9.16666667L16.5 20.1666667C16.5 23.21 18.9566667 25.6666667 22 25.6666667ZM31.7166667 20.1666667C31.7166667 25.6666667 27.06 29.5166667 22 29.5166667C16.94 29.5166667 12.2833333 25.6666667 12.2833333 20.1666667L9.16666667 20.1666667C9.16666667 26.4183333 14.1533333 31.5883333 20.1666667 32.4866667L20.1666667 38.5L23.8333333 38.5L23.8333333 32.4866667C29.8466667 31.6066667 34.8333333 26.4366667 34.8333333 20.1666667L31.7166667 20.1666667Z" - android:fillColor="@android:color/white" /> + android:width="32dp" + android:height="32dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M12,14c1.66,0 3,-1.34 3,-3V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6C9,12.66 10.34,14 12,14zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V5z"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M17,11c0,2.76 -2.24,5 -5,5s-5,-2.24 -5,-5H5c0,3.53 2.61,6.43 6,6.92V21h2v-3.08c3.39,-0.49 6,-3.39 6,-6.92H17z"/> </vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml b/packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml new file mode 100644 index 000000000000..9b48a70d9439 --- /dev/null +++ b/packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + + <corners + android:bottomLeftRadius="8dp" + android:topLeftRadius="8dp" /> + <solid android:color="@color/tv_audio_recording_indicator_background" /> + +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml b/packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml new file mode 100644 index 000000000000..03348756231b --- /dev/null +++ b/packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + + <corners + android:bottomRightRadius="8dp" + android:topRightRadius="8dp" /> + <solid android:color="@color/tv_audio_recording_indicator_background" /> + +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/tv_gradient_protection.xml b/packages/SystemUI/res/drawable/tv_ring_white.xml index ee5cbc7e6ba0..0f7cc1082f71 100644 --- a/packages/SystemUI/res/drawable/tv_gradient_protection.xml +++ b/packages/SystemUI/res/drawable/tv_ring_white.xml @@ -15,8 +15,11 @@ ~ limitations under the License. --> -<!-- gradient protection for cards --> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/tv_card_gradient_protection" - android:tileMode="repeat" -/> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + + <stroke + android:width="1dp" + android:color="@android:color/white" /> + +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/bubble_menu_view.xml b/packages/SystemUI/res/layout/bubble_menu_view.xml new file mode 100644 index 000000000000..24608d3e9611 --- /dev/null +++ b/packages/SystemUI/res/layout/bubble_menu_view.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<com.android.systemui.bubbles.BubbleMenuView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:background="#66000000" + android:visibility="gone" + android:id="@+id/bubble_menu_container"> + + <FrameLayout + android:layout_height="@dimen/individual_bubble_size" + android:layout_width="wrap_content" + android:background="#FFFFFF" + android:id="@+id/bubble_menu_view"> + + <ImageView + android:id="@*android:id/icon" + android:layout_width="@dimen/global_actions_grid_item_icon_width" + android:layout_height="@dimen/global_actions_grid_item_icon_height" + android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin" + android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin" + android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin" + android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin" + android:scaleType="centerInside" + android:tint="@color/global_actions_text" + /> + </FrameLayout> +</com.android.systemui.bubbles.BubbleMenuView> diff --git a/packages/SystemUI/res/layout/bubble_overflow_activity.xml b/packages/SystemUI/res/layout/bubble_overflow_activity.xml new file mode 100644 index 000000000000..4cee74615bd2 --- /dev/null +++ b/packages/SystemUI/res/layout/bubble_overflow_activity.xml @@ -0,0 +1,20 @@ +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/bubble_overflow_recycler" + android:scrollbars="vertical" + android:layout_width="wrap_content" + android:layout_height="match_parent"/> diff --git a/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml new file mode 100644 index 000000000000..f04226e7ceaf --- /dev/null +++ b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:padding="32dp"> + + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <LinearLayout + android:id="@+id/icon_texts_container" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <FrameLayout + android:layout_width="90dp" + android:layout_height="94dp"> + + <View + android:id="@+id/icon_container_bg" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/tv_rect_dark_left_rounded"/> + + <FrameLayout + android:id="@+id/icon_mic" + android:layout_width="70dp" + android:layout_height="70dp" + android:layout_marginLeft="12dp" + android:layout_marginTop="12dp" + android:layout_marginRight="8dp" + android:layout_marginBottom="12dp"> + + <View + android:layout_width="54dp" + android:layout_height="54dp" + android:layout_gravity="center" + android:background="@drawable/tv_circle_dark"/> + + <ImageView + android:id="@+id/pulsating_circle" + android:layout_width="54dp" + android:layout_height="54dp" + android:layout_gravity="center" + android:background="@drawable/tv_circle_white_translucent"/> + + <ImageView + android:layout_width="54dp" + android:layout_height="54dp" + android:layout_gravity="center" + android:src="@drawable/tv_ring_white"/> + + <ImageView + android:layout_width="32dp" + android:layout_height="32dp" + android:layout_gravity="center" + android:background="@drawable/tv_ic_mic_white"/> + </FrameLayout> + + </FrameLayout> + + <LinearLayout + android:id="@+id/texts_container" + android:layout_width="wrap_content" + android:layout_height="94dp" + android:background="@color/tv_audio_recording_indicator_background" + android:gravity="center_vertical" + android:orientation="vertical" + android:visibility="visible"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/mic_active" + android:textColor="@android:color/white" + android:fontFamily="sans-serif" + android:textSize="20dp"/> + + <TextView + android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:singleLine="true" + android:text="SomeApplication accessed your microphone" + android:textColor="@android:color/white" + android:fontFamily="sans-serif" + android:textSize="16dp"/> + + </LinearLayout> + + </LinearLayout> + + </FrameLayout> + + <View + android:id="@+id/bg_right" + android:layout_width="24dp" + android:layout_height="94dp" + android:background="@drawable/tv_rect_dark_right_rounded" + android:visibility="visible"/> + +</LinearLayout> diff --git a/packages/SystemUI/res/layout/tv_item_app_info.xml b/packages/SystemUI/res/layout/tv_item_app_info.xml deleted file mode 100644 index b40589ec80c6..000000000000 --- a/packages/SystemUI/res/layout/tv_item_app_info.xml +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2019 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="wrap_content" - android:layout_height="48dp" - android:layout_marginLeft="8dp" - android:paddingHorizontal="12dp" - android:gravity="center_vertical" - android:background="@drawable/tv_bg_item_app_info"> - - <ImageView - android:id="@+id/icon" - android:layout_width="24dp" - android:layout_height="24dp" - android:layout_marginRight="8dp"/> - - <TextView - android:id="@+id/title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textColor="@color/tv_audio_recording_bar_text" - android:fontFamily="sans-serif" - android:textSize="14sp"/> - -</LinearLayout> diff --git a/packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml b/packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml deleted file mode 100644 index b9dffbb4de20..000000000000 --- a/packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml +++ /dev/null @@ -1,63 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2019 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:orientation="vertical"> - - <!-- Gradient Protector --> - <View - android:layout_width="match_parent" - android:layout_height="102.5dp" - android:background="@drawable/tv_gradient_protection"/> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="72dp" - android:background="@color/tv_audio_recording_bar_background" - android:gravity="center_vertical" - android:orientation="horizontal"> - - <ImageView - android:layout_width="48dp" - android:layout_height="48dp" - android:layout_marginLeft="42dp" - android:layout_marginVertical="12dp" - android:padding="8dp" - android:background="@drawable/circle_red" - android:scaleType="centerInside" - android:src="@drawable/tv_ic_mic_white"/> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="24dp" - android:text="Audio recording by" - android:textColor="@color/tv_audio_recording_bar_text" - android:fontFamily="sans-serif" - android:textSize="14sp"/> - - <LinearLayout - android:id="@+id/container" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> - - </LinearLayout> - -</LinearLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index ef2d0610aef6..8f64aab3eca6 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Stelselnavigasie is opgedateer. Gaan na Instellings toe om veranderinge te maak."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gaan na Instellings toe om stelselnavigasie op te dateer"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Bystandmodus"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Die Android TV-toestel gaan binnekort afskakel; druk \'n knoppie om dit aan te hou."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Die toestel gaan binnekort afskakel; druk om dit aan te hou."</string> </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index d39f399e858c..d73c0ed17f3c 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"የስርዓት ዳሰሳ ተዘምኗል። ለውጦችን ለማድረግ ወደ ቅንብሮች ይሂዱ።"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"የስርዓት ዳሰሳን ለማዘመን ወደ ቅንብሮች ይሂዱ"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ተጠባባቂ"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"የAndroid TV መሣሪያው በቅርቡ ይጠፋል፣ እንደበራ ለማቆየት ይጫኑ።"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"መሣሪያው በቅርቡ ይጠፋል፤ እንደበራ ለማቆየት ይጫኑ።"</string> </resources> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 3fe4684494fa..68fe91ce4ed3 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -978,6 +978,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"تم تحديث التنقل داخل النظام. لإجراء التغييرات، يُرجى الانتقال إلى \"الإعدادات\"."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"الانتقال إلى \"الإعدادات\" لتعديل التنقل داخل النظام"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"وضع الاستعداد"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"سيتم إيقاف جهاز Android TV قريبًا، اضغط على أحد الأزرار لمواصلة تشغيله."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"سيتم إيقاف الجهاز قريبًا، اضغط لمواصلة تشغيله."</string> </resources> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index c711b4d22676..b55f4197f6a5 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -960,6 +960,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰা হ’ল। সলনি কৰিবলৈ ছেটিংসমূহ-লৈ যাওক।"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰিবলৈ ছেটিংসমূহ-লৈ যাওক"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ষ্টেণ্ডবাই"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ডিভাইচটো অতি সোনকালে অফ হ\'ব, এইটো অন ৰাখিবলৈ যিকোনো এটা বুটাম টিপক।"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"এই ডিভাইচটো অতি সোনকালে অফ হ\'ব, এইটো অন ৰাখিবলৈ টিপক।"</string> </resources> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index c90b67c94b60..95da98134a08 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistem naviqasiyası yeniləndi. Dəyişiklik etmək üçün Ayarlara daxil olun."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistem naviqasiyasını yeniləmək üçün Ayarlara keçin"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gözləmə rejimi"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV cihazı tezliklə sönəcək; aktiv saxlamaq üçün düyməyə basın."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Cihaz tezliklə sönəcək; aktiv saxlamaq üçün basın."</string> </resources> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index f0f72b5aaa43..7b909cf311bf 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -963,6 +963,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigacija sistema je ažurirana. Da biste uneli izmene, idite u Podešavanja."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Podešavanja da biste ažurirali navigaciju sistema"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravnosti"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV će se uskoro isključiti. Pritisnite dugme da bi ostao uključen."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Uređaj će se uskoro isključiti. Pritisnite da bi ostao uključen."</string> </resources> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index ee82d7680732..412fcb7430c6 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -970,6 +970,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацыя ў сістэме абноўлена. Каб унесці змяненні, перайдзіце ў Налады."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перайдзіце ў Налады, каб абнавіць параметры навігацыі ў сістэме"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Рэжым чакання"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Прылада Android TV неўзабаве выключыцца. Каб пакінуць яе ўключанай, націсніце кнопку."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Прылада неўзабаве выключыцца. Націсніце, каб пакінуць яе ўключанай."</string> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index b624dced4972..e9bf3c7a45ff 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Режимът за навигиране в системата е актуализиран. За да извършите промени, отворете настройките."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Отворете настройките, за да актуализирате режима за навигиране в системата"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим на готовност"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Устройството с Android TV скоро ще се изключи. Натиснете бутон, за да остане включено."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Устройството скоро ще се изключи. Натиснете, за да остане включено."</string> </resources> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 9dcdc592e76b..60b23d7b5e9a 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -960,6 +960,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"সিস্টেম নেভিগেশন আপডেট হয়েছে। পরিবর্তন করার জন্য সেটিংসে যান।"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"সিস্টেম নেভিগেশন আপডেট করতে সেটিংসে যান"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"স্ট্যান্ডবাই"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ডিভাইস শীঘ্রই বন্ধ হয়ে যাবে, চালু রাখতে বোতাম প্রেস করুন।"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ডিভাইস শীঘ্রই বন্ধ হয়ে যাবে, চালু রাখতে প্রেস করুন।"</string> </resources> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 7774ed61baa2..40f2d7c5e764 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -965,6 +965,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigiranje sistemom je ažurirano. Da izvršite promjene, idite u Postavke."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Postavke da ažurirate navigiranje sistemom"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV uređaj će se uskoro isključiti. Pritisnite dugme da ostane uključen."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Uređaj će se uskoro isključiti. Pritisnite da ostane uključen."</string> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 589eeed491c5..8e64a2e0674d 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"S\'ha actualitzat el sistema de navegació. Per fer canvis, ves a Configuració."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ves a Configuració per actualitzar el sistema de navegació"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"El dispositiu Android TV s\'apagarà aviat; prem un botó per mantenir-lo encès."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"El dispositiu s\'apagarà aviat; prem per mantenir-lo encès."</string> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index dcefc84c046f..2843bcd44f70 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -968,6 +968,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systémová navigace byla aktualizována. Chcete-li provést změny, přejděte do Nastavení."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Přejděte do Nastavení a aktualizujte systémovou navigaci"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostní režim"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Zařízení Android TV se brzy vypne, stisknutím tlačítka ho ponecháte zapnuté."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Zařízení se brzy vypne, stisknutím ho ponecháte zapnuté."</string> </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index ba38784f0821..da62c702d257 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigationen blev opdateret. Gå til Indstillinger for at foretage ændringer."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gå til Indstillinger for at opdatere systemnavigationen"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV-enheden slukker snart. Tryk på en knap for at holde den tændt."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Enheden slukker snart. Tryk for at holde den tændt."</string> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 70b4f08e32a5..7e54703c151b 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -962,6 +962,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemsteuerungseinstellungen wurden angepasst. Änderungen kannst du in den Einstellungen vornehmen."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gehe zu den Einstellungen, um die Systemsteuerung anzupassen"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Das Android TV-Gerät wird demnächst abgeschaltet. Drücke eine Taste, damit es eingeschaltet bleibt."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Das Gerät wird demnächst abgeschaltet. Drücke beispielsweise eine Taste oder berühre den Bildschirm, damit es eingeschaltet bleibt."</string> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 3c7105be054e..ab7f1e577219 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Η πλοήγηση συστήματος ενημερώθηκε. Για να κάνετε αλλαγές, μεταβείτε στις Ρυθμίσεις."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Μεταβείτε στις Ρυθμίσεις για να ενημερώσετε την πλοήγηση συστήματος"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Κατάσταση αναμονής"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Η συσκευή Android TV σύντομα θα απενεργοποιηθεί. Πατήστε ένα κουμπί για να την κρατήσετε ενεργοποιημένη."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Η συσκευή σύντομα θα απενεργοποιηθεί. Πατήστε για να την κρατήσετε ενεργοποιημένη."</string> </resources> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index e6a7d6c220c2..35d4b4f5c070 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string> </resources> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 858de044aa8a..9ac53cd816ad 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index e6a7d6c220c2..35d4b4f5c070 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string> </resources> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index e6a7d6c220c2..35d4b4f5c070 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string> </resources> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index a6abc8c544c7..f7c937b45c62 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -953,6 +953,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string> </resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index db6ccb747233..1787643f3e68 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se actualizó el sistema de navegación. Para hacer cambios, ve a Configuración."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Configuración para actualizar la navegación del sistema"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Pronto se apagará el dispositivo Android TV; presiona un botón para mantenerlo encendido."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Pronto se apagará el dispositivo; presiona para mantenerlo encendido."</string> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index ef52829c653b..9a9f05193aa9 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se ha actualizado la navegación del sistema. Para hacer cambios, ve a Ajustes."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Ajustes para actualizar la navegación del sistema"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"El dispositivo Android TV pronto se apagará; pulsa un botón para evitarlo."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"El dispositivo pronto se apagará si no interactúas con él."</string> </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 57eed439ea97..31bffa34ce5c 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Süsteemis navigeerimine on värskendatud. Muutmiseks avage jaotis Seaded."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Süsteemi navigeerimise värskendamiseks avage jaotis Seaded"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ooterežiim"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV seade lülitub varsti välja; selle aktiivsena hoidmiseks vajutage nuppu."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Seade lülitub värsti välja; selle aktiivsena hoidmiseks vajutage nuppu."</string> </resources> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 9ffe463c6afb..fa243887b648 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Eguneratu da sistemaren nabigazioa. Aldaketak egiteko, joan Ezarpenak atalera."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistemaren nabigazioa eguneratzeko, joan Ezarpenak atalera"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Egonean"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV gailua laster itzaliko da; sakatu botoi bat piztuta mantentzeko."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Gailua laster itzaliko da; sakatu piztuta mantentzeko."</string> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index ea5674875c34..4ce5b27cb129 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"پیمایش سیستم بهروزرسانی شد. برای انجام تغییرات به «تنظیمات» بروید."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"برای بهروزرسانی پیمایش سیستم، به «تنظیمات» بروید"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"آمادهبهکار"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"دستگاه Android TV بهزودی خاموش میشود، برای روشن نگهداشتن آن، دکمهای را فشار دهید."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"دستگاه بهزودی خاموش میشود، برای روشن نگهداشتن آن فشار دهید."</string> </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 32f2eec1cd58..8912db8b7440 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Järjestelmän navigointitapa vaihdettu. Voit muuttaa sitä asetuksista."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Vaihda järjestelmän navigointitapaa asetuksista"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Virransäästötila"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ‑laite sammuu pian. Pidä se päällä painamalla painiketta."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Laite sammuu pian. Pidä se päällä painamalla jotakin."</string> </resources> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index a144ddd293c3..2bf724c16c57 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"La navigation système a été mise à jour. Pour apporter des modifications, accédez au menu Paramètres."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez au menu Paramètres pour mettre à jour la navigation système"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Veille"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"L\'appareil Android TV va bientôt s\'éteindre. Appuyez sur un bouton pour le laisser allumé."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"L\'appareil va bientôt s\'éteindre. Interagissez avec lui pour le laisser allumé."</string> </resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index b12641355002..d2614defd013 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigation système mise à jour. Pour apporter des modifications, accédez aux paramètres."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez aux paramètres pour mettre à jour la navigation système"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Mode Veille imminent"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"L\'appareil Android TV va bientôt passer en mode Veille. Appuyez sur un bouton pour qu\'il reste allumé."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"L\'appareil va bientôt passer en mode Veille. Appuyez dessus pour qu\'il reste allumé."</string> </resources> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 88bfa0565c49..a7a5726c2d81 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Actualizouse a navegación do sistema. Para facer cambios, vai a Configuración."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Para actualizar a navegación do sistema, vai a Configuración"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Pronto se apagará o dispositivo Android TV. Preme un botón para mantelo acendido."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Pronto se apagará o dispositivo. Tócao para mantelo acendido."</string> </resources> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 6f46b84f99e4..69c50e134ffa 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -960,6 +960,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"સિસ્ટમ નૅવિગેશન અપડેટ કર્યું. ફેરફારો કરવા માટે, સેટિંગ પર જાઓ."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"સિસ્ટમ નૅવિગેશનને અપડેટ કરવા માટે સેટિંગ પર જાઓ"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"સ્ટૅન્ડબાય"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android ટીવી ડિવાઇસ ટૂંક સમયમાં બંધ થશે; તેને ચાલુ રાખવા માટે બટન દબાવો."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ડિવાઇસ ટૂંક સમયમાં બંધ થશે; તેને ચાલુ રાખવા માટે દબાવો."</string> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 1a5ce8e5a2f5..3fc78706d4bd 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेविगेशन अपडेट हो गया. बदलाव करने के लिए \'सेटिंग\' पर जाएं."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेविगेशन अपडेट करने के लिए \'सेटिंग\' में जाएं"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टैंडबाई"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV डिवाइस जल्द ही बंद हो जाएगा. इसे चालू रखने के लिए किसी बटन को दबाएं."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"डिवाइस जल्द ही बंद हो जाएगा. इसे चालू रखने के लिए स्क्रीन पर टैप करें या किसी बटन को दबाएं."</string> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index e270f0f04f7c..f19bdf5f95a5 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -963,6 +963,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Ažurirana je navigacija sustavom. Možete je promijeniti u Postavkama."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Navigaciju sustavom možete ažurirati u Postavkama"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Uređaj Android TV uskoro će se isključiti. Pritisnite gumb da bi ostao uključen."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Uređaj će se uskoro isključiti. Pritisnite da bi ostao uključen."</string> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 5ff99c92af71..8624670ea0dc 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"A rendszer-navigáció módja megváltozott. Módosításához nyissa meg a Beállításokat."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"A rendszer-navigációs lehetőségeket a Beállításokban módosíthatja"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Készenléti mód"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Az Android TV eszköz hamarosan kikapcsol. Nyomja meg valamelyik gombot, hogy bekapcsolva tarthassa."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Az eszköz hamarosan kikapcsol. Nyomja meg, hogy bekapcsolva tarthassa."</string> </resources> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index cf5ba2e70123..c02199e5316c 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Համակարգի նավիգացիան թարմացվեց: Փոփոխություններ անելու համար անցեք կարգավորումներ:"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Թարմացրեք համակարգի նավիգացիան կարգավորումներում"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Սպասման ռեժիմ"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV սարքը շուտով կանջատվի: Սեղմեք որևէ կոճակ՝ միացրած թողնելու համար:"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Սարքը շուտով կանջատվի: Սեղմեք՝ միացրած թողնելու համար:"</string> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index bb6249873d61..99fa8454d78f 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigasi sistem diupdate. Untuk melakukan perubahan, buka Setelan."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Buka Setelan untuk mengupdate navigasi sistem"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Siaga"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Perangkat Android TV akan segera dinonaktifkan; tekan tombol untuk terus menyalakannya."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Perangkat akan segera dinonaktifkan, tekan untuk terus menyalakannya."</string> </resources> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index d0deac349e7e..cd23616c4d7d 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Kerfisstjórnun uppfærð. Þú getur breytt þessu í stillingunum."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Farðu í stillingar til að uppfæra kerfisstjórnun"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Biðstaða"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV tækið slekkur á sér fljótlega. Ýttu á takka til að það slokkni ekki á því."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Tækið slekkur á sér fljótlega. Ýttu á takka til að það slokkni ekki á því."</string> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 6e370ac5d2d5..9429c04de8f8 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigazione del sistema aggiornata. Per apportare modifiche, usa le Impostazioni."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Usa le Impostazioni per aggiornare la navigazione del sistema"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"A breve il dispositivo Android TV si spegnerà. Premi un pulsante per tenerlo acceso."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"A breve il dispositivo si spegnerà. Premi per tenerlo acceso."</string> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index de0ebab5d1be..b2da88a99f05 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -968,6 +968,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"הניווט במערכת עודכן. אפשר לערוך שינויים דרך ההגדרות."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"יש לעבור להגדרות כדי לעדכן את הניווט במערכת"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"המתנה"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"מכשיר Android TV ייכבה בקרוב. יש ללחוץ על לחצן כלשהו כדי שהוא ימשיך לפעול."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"המכשיר ייכבה בקרוב, יש ללחוץ כדי שהוא ימשיך לפעול."</string> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 4703f5e3cd6d..94dce862e742 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"システム ナビゲーションを更新しました。変更するには [設定] に移動してください。"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"システム ナビゲーションを更新するには [設定] に移動してください"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"スタンバイ"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV デバイスはまもなく OFF になります。ON 状態を維持するには、ボタンを押してください。"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"このデバイスはまもなく OFF になります。ON 状態を維持するには、ボタンを押してください。"</string> </resources> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 30c34baff2a5..d1e37a4810cb 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"სისტემური ნავიგაცია განახლდა. ცვლილებების შესატანად გადადით პარამეტრებზე."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"სისტემური ნავიგაციის გასაახლებლად გადადით პარამეტრებზე"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"მოლოდინის რეჟიმი"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV მოწყობილობა მალე გამოირთვება, დააჭირეთ ღილაკს, რომ ჩართული დარჩეს."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"მოწყობილობა მალე გამოირთვება, დააჭირეთ, რომ ჩართული დარჩეს."</string> </resources> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index cb4b39337cdd..c77a07566224 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Жүйе навигациясы жаңартылды. Өзгерту енгізу үшін \"Параметрлер\" бөліміне өтіңіз."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Жүйе навигациясын жаңарту үшін \"Параметрлер\" бөліміне өтіңіз."</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Күту режимі"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV құрылғысы жақын арада өшеді. Оны қосулы қалдыру үшін басыңыз."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Құрылғы жақын арада өшеді. Оны қосулы қалдыру үшін басыңыз."</string> </resources> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 0d9337b13db8..0cb691092a59 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"បានធ្វើបច្ចុប្បន្នភាពការរុករកក្នុងប្រព័ន្ធ។ ដើម្បីធ្វើការផ្លាស់ប្ដូរ សូមចូលទៅកាន់ការកំណត់។"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ចូលទៅកាន់ការកំណត់ ដើម្បីធ្វើបច្ចុប្បន្នភាពការរុករកក្នុងប្រព័ន្ធ"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ផ្អាកដំណើរការ"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"ឧបករណ៍ Android TV នឹងបិទក្នុងពេលឆាប់ៗនេះ សូមចុចប៊ូតុងដើម្បីបន្តបើកឧបករណ៍។"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ឧបករណ៍នឹងបិទក្នុងពេលឆាប់ៗនេះ សូមចុចដើម្បីបន្តបើកឧបករណ៍។"</string> </resources> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 3fbe942eb2de..c736240a3104 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ ಅಪ್ಡೇಟ್ ಮಾಡಲಾಗಿದೆ ಬದಲಾವಣೆಗಳನ್ನು ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ್ ಅಪ್ಡೇಟ್ ಮಾಡಲು ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ಸ್ಟ್ಯಾಂಡ್ಬೈ"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"ಈ Android TV ಸಾಧನವು ಶೀಘ್ರವೇ ಆಫ್ ಆಗುತ್ತದೆ; ಇದನ್ನು ಆನ್ನಲ್ಲಿಡಲು ಬಟನ್ ಅನ್ನು ಒತ್ತಿರಿ."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ಈ ಸಾಧನವು ಶೀಘ್ರವೇ ಆಫ್ ಆಗುತ್ತದೆ; ಇದನ್ನು ಆನ್ನಲ್ಲಿಡಲು ಒತ್ತಿರಿ."</string> </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 7923c6f2bbeb..a60f73615508 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"시스템 탐색이 업데이트되었습니다. 변경하려면 설정으로 이동하세요."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"설정으로 이동하여 시스템 탐색을 업데이트하세요."</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"대기"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV가 곧 꺼집니다. 계속 켜 두려면 버튼을 누르세요."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"기기가 곧 꺼집니다. 계속 켜 두려면 누르세요."</string> </resources> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index ba029f15f86a..80aa6a1fcfd4 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Тутум чабыттоосу жаңыртылды. Өзгөртүү үчүн, Жөндөөлөргө өтүңүз."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Тутум чабыттоосун жаңыртуу үчүн Жөндөөлөргө өтүңүз"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Көшүү режими"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV түзмөгү жакында өчүрүлөт, аны күйүк боюнча калтыруу үчүн баскычты басыңыз."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Түзмөк жакында өчүрүлөт, күйүк боюнча калтыруу үчүн басып коюңуз."</string> </resources> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 4376cc5830c2..8b3be6498994 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ອັບເດດການນຳທາງລະບົບແລ້ວ. ເພື່ອປ່ຽນແປງ, ກະລຸນາໄປທີ່ການຕັ້ງຄ່າ."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ໄປທີ່ການຕັ້ງຄ່າເພື່ອອັບເດດການນຳທາງລະບົບ"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ສະແຕນບາຍ"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"ອຸປະກອນ Android TV ຈະປິດໃນອີກບໍ່ດົນ, ກົດປຸ່ມໃດໜຶ່ງເພື່ອເປີດມັນໄວ້ຕໍ່."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ອຸປະກອນຈະປິດໃນອີກບໍ່ດົນ, ກົດເພື່ອເປີດມັນໄວ້ຕໍ່."</string> </resources> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 2534a3bbfcfe..c7282cd94836 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -968,6 +968,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistemos naršymo funkcijos atnaujintos. Jei norite pakeisti, eikite į skiltį „Nustatymai“."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Eikite į skiltį „Nustatymai“, kad atnaujintumėte sistemos naršymo funkcijas"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Budėjimo laikas"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"„Android TV“ įrenginys netrukus išsijungs. Paspauskite mygtuką, kad jis liktų įjungtas."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Įrenginys netrukus išsijungs. Paspauskite, kad jis liktų įjungtas."</string> </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 9604dc249baf..e99462b97cce 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -963,6 +963,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistēmas navigācija ir atjaunināta. Lai veiktu izmaiņas, atveriet iestatījumus."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Atveriet iestatījumus, lai atjauninātu sistēmas navigāciju"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gaidstāve"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ierīce drīz izslēgsies. Nospiediet pogu, lai tā paliktu ieslēgta."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Ierīce drīz izslēgsies. Nospiediet, lai tā paliktu ieslēgta."</string> </resources> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index f9c5c4a0c942..a607f75054d0 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навигацијата на системот е ажурирана. За да извршите промени, одете во „Поставки“."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Одете во „Поставки“ за да ја ажурирате навигацијата на системот"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Подготвеност"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Уредот со Android TV наскоро ќе се исклучи, притиснете копче за да остане вклучен."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Уредот наскоро ќе се исклучи, притиснете за да остане вклучен."</string> </resources> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index fd3f16c0801d..53ce5aba07c2 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -960,6 +960,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"സിസ്റ്റം നാവിഗേഷൻ അപ്ഡേറ്റ് ചെയ്തു. മാറ്റങ്ങൾ വരുത്താൻ ക്രമീകരണത്തിലേക്ക് പോവുക."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"സിസ്റ്റം നാവിഗേഷൻ അപ്ഡേറ്റ് ചെയ്യാൻ ക്രമീകരണത്തിലേക്ക് പോവുക"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"സ്റ്റാൻഡ്ബൈ"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android ടിവി ഉടൻ ഓഫാകും, ഓണാക്കി നിർത്താൻ ഒരു ബട്ടൺ അമർത്തുക."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ഉപകരണം ഉടൻ ഓഫാകും, ഓണാക്കി നിർത്താൻ അമർത്തുക."</string> </resources> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 0939c7255de0..75af9cd5e272 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Системийн навигацыг шинэчиллээ. Өөрчлөхийн тулд Тохиргоо руу очно уу."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Системийн навигацыг шинэчлэхийн тулд Тохиргоо руу очно уу"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Зогсолтын горим"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Андройд ТВ төхөөрөмж удахгүй унтрах тул асаалттай хэвээр байлгахын тулд товчлуур дээр дарна уу."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Төхөөрөмж удахгүй унтрах тул асаалттай хэвээр байлгахын тулд дарна уу."</string> </resources> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 5326e3799f3c..089df331ce72 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेव्हिगेशन अपडेट केले. बदल करण्यासाठी, सेटिंग्जवर जा."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेव्हिगेशन अपडेट करण्यासाठी सेटिंग्जवर जा"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टँडबाय"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV डिव्हाइस लवकरच बंद होणार आहे; सुरू ठेवण्यासाठी बटण दाबा."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"डिव्हाइस लवकरच बंद होणार आहे; सुरू ठेवण्यासाठी स्क्रीनवर किंवा बटण दाबा."</string> </resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 25d73c01412c..3073c9f65491 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigasi sistem dikemas kini. Untuk membuat perubahan, pergi ke Tetapan."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Pergi ke Tetapan untuk mengemas kini navigasi sistem"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tunggu sedia"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Peranti Android TV akan mati tidak lama lagi; tekan butang untuk memastikan peranti terus hidup."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Peranti akan mati tidak lama lagi; tekan untuk memastikan peranti terus hidup."</string> </resources> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index beca4c485557..9fcb86e04617 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"စနစ်လမ်းညွှန်ခြင်း အပ်ဒိတ်လုပ်ပြီးပါပြီ။ အပြောင်းအလဲများ ပြုလုပ်ရန် \'ဆက်တင်များ\' သို့သွားပါ။"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"စနစ်လမ်းညွှန်ခြင်း အပ်ဒိတ်လုပ်ရန် \'ဆက်တင်များ\' သို့သွားပါ"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"အသင့်အနေအထား"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV စက်သည် မကြာမီ ပိတ်သွားပါမည်၊ ဆက်ဖွင့်ထားရန် ခလုတ်တစ်ခုနှိပ်ပါ။"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"စက်သည် မကြာမီ ပိတ်သွားပါမည်၊ ဆက်ဖွင့်ထားပါ။"</string> </resources> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index a07451db071e..9a9854b716a3 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigeringen er oppdatert. For å gjøre endringer, gå til Innstillinger."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gå til Innstillinger for å oppdatere systemnavigeringen"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ventemodus"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV-enheten slås snart av. Trykk på en knapp for å holde den på."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Enheten slås snart av. Trykk for å holde den på."</string> </resources> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 39e612a6cceb..fa1fa56a4a15 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"प्रणालीको नेभिगेसन अद्यावधिक गरियो। परिवर्तन गर्न सेटिङमा जानुहोस्।"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"प्रणालीको नेभिगेसन अद्यावधिक गर्न सेटिङमा जानुहोस्"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्ट्यान्डबाई"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV यन्त्र चाँडै निष्क्रिय हुने छ; सक्रिय राख्न कुनै बटन थिच्नुहोस्।"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"यो यन्त्र चाँडै निष्क्रिय हुने छ; सक्रिय राख्न थिच्नुहोस्।"</string> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index a1b7c293b1c1..9aa9f1e8cfc7 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systeemnavigatie geüpdatet. Als je wijzigingen wilt aanbrengen, ga je naar Instellingen."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ga naar Instellingen om de systeemnavigatie te updaten"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stand-by"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Het Android TV-apparaat wordt binnenkort uitgeschakeld. Druk op een knop om het ingeschakeld te houden."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Het apparaat wordt binnenkort uitgeschakeld. Druk om het ingeschakeld te houden."</string> </resources> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 5a9d136fe353..4d467fe9033b 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -960,6 +960,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍ଡେଟ୍ ହୋଇଛି। ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ, ସେଟିଂସ୍କୁ ଯାଆନ୍ତୁ।"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍ଡେଟ୍ କରିବା ପାଇଁ ସେଟିଂସ୍କୁ ଯାଆନ୍ତୁ"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ଷ୍ଟାଣ୍ଡବାଏ"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android ଟିଭି ଡିଭାଇସ୍ ଶୀଘ୍ର ବନ୍ଦ ହୋଇଯିବ; ଏହା ଚାଲୁ ରଖିବା ପାଇଁ ଏକ ବଟନ୍ ଦବାନ୍ତୁ।"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ଡିଭାଇସ୍ ଶୀଘ୍ର ବନ୍ଦ ହୋଇଯିବ; ଚାଲୁ ରଖିବା ପାଇଁ ଦବାନ୍ତୁ।"</string> </resources> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 84052d7e38ad..cce1df3f726e 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -960,6 +960,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਅੱਪਡੇਟ ਹੋ ਗਿਆ। ਤਬਦੀਲੀਆਂ ਕਰਨ ਲਈ, ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ।"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ਸਟੈਂਡਬਾਈ"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ਡੀਵਾਈਸ ਜਲਦ ਹੀ ਬੰਦ ਹੋ ਜਾਵੇਗਾ; ਇਸਨੂੰ ਚਾਲੂ ਰੱਖਣ ਲਈ ਕੋਈ ਬਟਨ ਦਬਾਓ।"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ਡੀਵਾਈਸ ਜਲਦ ਹੀ ਬੰਦ ਹੋ ਜਾਵੇਗਾ, ਇਸਨੂੰ ਚਾਲੂ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 4e7b0de986bf..0a9c1745e510 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -968,6 +968,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Nawigacja w systemie została zaktualizowana. Aby wprowadzić zmiany, otwórz Ustawienia."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Otwórz Ustawienia, by zaktualizować nawigację w systemie"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tryb gotowości"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Urządzenie z Androidem TV za chwilę się wyłączy. Naciśnij przycisk, by pozostało włączone."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Urządzenie za chwilę się wyłączy. Naciśnij, by pozostało włączone."</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 79dff12a0bca..9459e81a8826 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navegação no sistema atualizada. Se quiser alterá-la, acesse as configurações."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Acesse as configurações para atualizar a navegação no sistema"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"O dispositivo Android TV entrará no modo de espera em breve. Pressione um botão para mantê-lo ativado."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"O dispositivo entrará no modo de espera em breve. Pressione para mantê-lo ativado."</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index ab1fc966b642..b235bda4c4bc 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"A navegação no sistema foi atualizada. Para efetuar alterações, aceda às Definições."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Aceda às Definições para atualizar a navegação no sistema."</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"O dispositivo Android TV irá desligar-se brevemente. Prima um botão para o manter ligado."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"O dispositivo irá desligar-se brevemente. Prima para o manter ligado."</string> </resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 79dff12a0bca..9459e81a8826 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navegação no sistema atualizada. Se quiser alterá-la, acesse as configurações."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Acesse as configurações para atualizar a navegação no sistema"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"O dispositivo Android TV entrará no modo de espera em breve. Pressione um botão para mantê-lo ativado."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"O dispositivo entrará no modo de espera em breve. Pressione para mantê-lo ativado."</string> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index c2803aa30d6b..ea82ec373c67 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -963,6 +963,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigarea în sistem a fost actualizată. Pentru a face modificări, accesați Setările."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accesați Setările pentru a actualiza navigarea în sistem"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Dispozitivul Android TV se va opri în curând. Apăsați un buton pentru a-l menține pornit."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Dispozitivul se va opri în curând. Apăsați pentru a-l menține pornit."</string> </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 9d0b2a92476d..fddb73525b37 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -968,6 +968,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Параметры навигации в системе обновлены. Чтобы изменить их, перейдите в настройки."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Чтобы обновить параметры навигации в системе, перейдите в настройки."</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Переход в режим ожидания"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Устройство Android TV скоро выключится. Чтобы этого не произошло, нажмите любую кнопку."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Устройство скоро выключится. Чтобы этого не произошло, нажмите любую кнопку или коснитесь экрана."</string> </resources> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 1b4db048b302..c28b189e2718 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"පද්ධති සංචලනය යාවත්කාලීන කළා. වෙනස්කම් සිදු කිරීමට, සැකසීම් වෙත යන්න."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"පද්ධති සංචලනය යාවත්කාලීන කිරීමට සැකසීම් වෙත යන්න"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"පොරොත්තු"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV උපාංගය ඉක්මනින් ක්රියා විරහිත වනු ඇත; එය දිගටම ක්රියාත්මක කර තැබීමට බොත්තමක් ඔබන්න."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"උපාංගය ඉක්මනින් ක්රියා විරහිත වනු ඇත; එය දිගටම ක්රියාත්මක කර තැබීමට ඔබන්න."</string> </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 9cf97c95b89b..ca929a0d7d82 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -968,6 +968,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigácia v systéme bola aktualizovaná. Ak chcete vykonať zmeny, prejdite do Nastavení."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Prejdite do Nastavení a aktualizujte navigáciu v systéme"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostný režim"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Zariadenie Android TV sa čoskoro vypne. Ak ho chcete ponechať zapnuté, stlačte ľubovoľné tlačidlo."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Zariadenie sa čoskoro vypne. Ak ho chcete ponechať zapnuté, stlačte ľubovoľné tlačidlo."</string> </resources> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 690e2979fcb4..5b65bbcf2189 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -968,6 +968,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Krmarjenje po sistemu je posodobljeno. Če želite opraviti spremembe, odprite nastavitve."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Če želite posodobiti krmarjenje po sistemu, odprite nastavitve"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravljenosti"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Naprava Android TV se bo kmalu izklopila. Če tega ne želite, pritisnite poljuben gumb."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Naprava se bo kmalu izklopila. Če tega ne želite, pritisnite poljuben gumb."</string> </resources> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 4ef95c58eeba..b1be1fde1fb5 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigimi i sistemit u përditësua. Për të bërë ndryshime, shko te \"Cilësimet\"."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Shko te \"Cilësimet\" për të përditësuar navigimin e sistemit"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Në gatishmëri"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Pajisja Android TV do të fiket së shpejti. Shtyp një buton për ta mbajtur të ndezur."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Pajisja do të fiket së shpejti. Shtype për ta mbajtur të ndezur."</string> </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 19bcca80feeb..26c6220fe3c3 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -963,6 +963,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навигација система је ажурирана. Да бисте унели измене, идите у Подешавања."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Идите у Подешавања да бисте ажурирали навигацију система"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Стање приправности"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ће се ускоро искључити. Притисните дугме да би остао укључен."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Уређај ће се ускоро искључити. Притисните да би остао укључен."</string> </resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 1177000ade18..4f32f0374421 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigeringen har uppdaterats. Öppna inställningarna om du vill ändra något."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Öppna inställningarna och uppdatera systemnavigeringen"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Viloläge"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV-enheten stängs snart av. Tryck på en knapp för att behålla den på."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Enheten stängs snart av. Tryck för att behålla den på."</string> </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index bf85374af9ec..921bdd959dbb 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Umesasisha usogezaji kwenye mfumo. Ili ufanye mabadiliko, nenda kwenye Mipangilio."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Nenda kwenye mipangilio ili usasishe usogezaji kwenye mfumo"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Hali tuli"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Kifaa cha Android TV kitazima hivi karibuni; bonyeza kitufe ili kisizime."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Kifaa kitazima hivi karibuni; bonyeza ili kisizime."</string> </resources> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 0990b7fdf725..5ca715b7efe7 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"சிஸ்டம் நேவிகேஷன் மாற்றப்பட்டது. மாற்றங்களைச் செய்ய ‘அமைப்புகளுக்குச்’ செல்லவும்."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"சிஸ்டம் நேவிகேஷனை மாற்ற ’அமைப்புகளுக்குச்’ செல்லவும்"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"இயக்க நேரம்"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV விரைவில் ஆஃப் ஆகலாம். இதைத் தொடர்ந்து ஆனில் வைக்க ஒரு பட்டனைத் தட்டவும்."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"இந்தச் சாதனம் விரைவில் ஆஃப் ஆகலாம், இதைத் தொடர்ந்து ஆனில் வைக்கத் தட்டவும்."</string> </resources> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 21e915c2188d..07fef971ca08 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"సిస్టమ్ నావిగేషన్ అప్డేట్ చేయబడింది. మార్పులు చేయడానికి, సెట్టింగ్లకు వెళ్లండి."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"సిస్టమ్ నావిగేషన్ను అప్డేట్ చేయడానికి సెట్టింగ్లకు వెళ్లండి"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"స్టాండ్బై"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV పరికరం త్వరలో ఆఫ్ అయిపోతుంది; దాన్ని ఆన్లో ఉంచడానికి బటన్ను నొక్కండి."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"పరికరం త్వరలో ఆఫ్ అయిపోతుంది; దీన్ని ఆన్లో ఉంచడానికి నొక్కండి."</string> </resources> diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml new file mode 100644 index 000000000000..27db294a98d8 --- /dev/null +++ b/packages/SystemUI/res/values-television/config.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2019, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources> + <!-- SystemUI Services: The classes of the stuff to start. --> + <string-array name="config_systemUIServiceComponents" translatable="false"> + <item>com.android.systemui.volume.VolumeUI</item> + <item>com.android.systemui.stackdivider.Divider</item> + <item>com.android.systemui.statusbar.tv.TvStatusBar</item> + <item>com.android.systemui.usb.StorageNotification</item> + <item>com.android.systemui.power.PowerUI</item> + <item>com.android.systemui.media.RingtonePlayer</item> + <item>com.android.systemui.keyboard.KeyboardUI</item> + <item>com.android.systemui.pip.PipUI</item> + <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item> + <item>@string/config_systemUIVendorServiceComponent</item> + <item>com.android.systemui.SliceBroadcastRelayHandler</item> + <item>com.android.systemui.SizeCompatModeActivityController</item> + <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item> + </string-array> +</resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 45cfe9276b39..14b7d746f7f0 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"อัปเดตการไปยังส่วนต่างๆ ของระบบแล้ว หากต้องการเปลี่ยนแปลง ให้ไปที่การตั้งค่า"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ไปที่การตั้งค่าเพื่ออัปเดตการไปยังส่วนต่างๆ ของระบบ"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"สแตนด์บาย"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"อุปกรณ์ Android TV จะปิดเครื่องในอีกไม่ช้า กดปุ่มเพื่อเปิดอุปกรณ์ต่อไป"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"อุปกรณ์จะปิดเครื่องในอีกไม่ช้า กดเพื่อเปิดอุปกรณ์ต่อไป"</string> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index bb150fc2bbad..382126207263 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Na-update na ang pag-navigate ng system. Para gumawa ng mga pagbabago, pumunta sa Mga Setting."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Pumunta sa Mga Setting para i-update ang pag-navigate sa system"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Naka-standby"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Mao-off na ang Android TV device; pumindot ng button para panatilihin itong naka-on."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Mao-off na ang device; pumindot para panatilihin itong naka-on."</string> </resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 5a0ede08c4b4..3dddbf5e70d0 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistemde gezinme yöntemi güncellendi. Değişiklik yapmak için Ayarlar\'a gidin."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistemde gezinme yöntemini güncellemek için Ayarlar\'a gidin"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Beklemeye alınıyor"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV cihazı kısa süre içinde kapanacak. Cihazınızı açık tutmak için bir düğmeye basın."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Cihaz kısa süre içinde kapanacak. Cihazı açık tutmak için düğmeye basın."</string> </resources> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index eddc4031a37f..a3e9e6280d29 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -968,6 +968,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацію в системі оновлено. Щоб внести зміни, перейдіть у налаштування."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перейдіть у налаштування, щоб оновити навігацію в системі"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим очікування"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Незабаром пристрій Android TV буде вимкнено. Натисніть кнопку, щоб цього не сталося."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Незабаром пристрій буде вимкнено. Натисніть, щоб цього не сталося."</string> </resources> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 3962d4f83bc3..e30b9aeaa85f 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"سسٹم نیویگیشن اپ ڈیٹ کیا گیا۔ تبدیلیاں کرنے کے لیے، ترتیبات پر جائیں۔"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"سسٹم نیویگیشن اپ ڈیٹ کرنے کے لیے ترتیبات پر جائیں"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"اسٹینڈ بائی"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV آلہ جلد ہی بند ہوجائے گا آن رکھنے کے ليے بٹن دبائیں۔"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"آلہ جلد ہی بند ہوجائے گا اسے آن رکھنے کے ليے دبائیں۔"</string> </resources> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 2f848394d93b..ec8639b0f746 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Tizim navigatsiyasi yangilandi. Buni Sozlamalar orqali oʻzgartirishingiz mumkin."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Tizim navigatsiyasini yangilash uchun Sozlamalarni oching"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Kutib turing"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV qurilmasi oʻchish arafasida, yoniq qolishi uchun istalgan tugmani bosing."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Qurilma oʻchish arafasida, yoniq qolishi uchun istalgan tugmani bosing."</string> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index f966c2efa858..9291563f5268 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -960,6 +960,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Đã cập nhật chế độ di chuyển trên hệ thống. Để thay đổi, hãy chuyển đến phần Cài đặt."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Chuyển đến phần Cài đặt để cập nhật chế độ di chuyển trên hệ thống"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Chế độ chờ"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Thiết bị Android TV sẽ sớm tắt. Hãy nhấn vào một nút để thiết bị vẫn bật."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Thiết bị sẽ sớm tắt. Hãy nhấn vào một nút để thiết bị vẫn bật."</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 64cf56ebe075..55db2b559281 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系统导航已更新。要进行更改,请转到“设置”。"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"转到“设置”即可更新系统导航"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待机"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV 设备即将关闭;按一下相应的按钮即可让设备保持开启状态。"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"设备即将关闭;按一下即可让设备保持开启状态。"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index a49bc64d575f..8a28aef0be13 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系統導覽已更新。如需變更,請前往「設定」。"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"前往「設定」更新系統導覽"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV 裝置即將關閉,按下按鈕即可保持開啟。"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"裝置即將關閉,輕按即可保持開啟。"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 2f468d049b06..79f336d50be9 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系統操作機制已更新。如要進行變更,請前往「設定」。"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"請前往「設定」更新系統操作機制"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV 裝置即將進入待機模式。如要讓裝置保持開啟狀態,請按下任一按鈕。"</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"裝置即將進入待機模式。如要讓裝置保持開啟狀態,請輕觸螢幕或按下按鈕。"</string> </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 2ee89dbeed09..bc3fcc0f71a5 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -958,6 +958,4 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Ukuzulazula kwesistimu kubuyekeziwe. Ukuze wenze ushintsho, hamba kokuthi Izilungiselelo."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Hamba kuzilungiselelo ukuze ubuyekeze ukuzulazula kwesistimu"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ilindile"</string> - <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Idivayisi ye-Android TV maduze izovalwa, cindezela inkinobho ukuze uyigcine ivuliwe."</string> - <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Idivayisi maduze izovalwa, cindezela ukuze uyigcine ivuliwe."</string> </resources> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index 6becd21984b9..79629e4c6d7e 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -154,12 +154,5 @@ <declare-styleable name="CaptionsToggleImageButton"> <attr name="optedOut" format="boolean" /> </declare-styleable> - - <!-- Theme attributes used to style the appearance of expanded Bubbles --> - <declare-styleable name="BubbleExpandedView"> - <attr name="android:colorBackgroundFloating" /> - <attr name="android:dialogCornerRadius" /> - </declare-styleable> - </resources> diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml index db225428a348..53cd9716c98e 100644 --- a/packages/SystemUI/res/values/colors_tv.xml +++ b/packages/SystemUI/res/values/colors_tv.xml @@ -22,13 +22,9 @@ <color name="recents_tv_dismiss_text_color">#7FEEEEEE</color> <color name="recents_tv_text_shadow_color">#7F000000</color> - - <!-- Text color used in audio recording bar: G50 --> - <color name="tv_audio_recording_bar_text">#FFF8F9FA</color> - <!-- Background color for a chip in audio recording bar: G800 --> - <color name="tv_audio_recording_bar_chip_background">#FF3C4043</color> - <!-- Audio recording bar background color: G900 --> - <color name="tv_audio_recording_bar_background">#FF202124</color> + <!-- Background color for audio recording indicator (G800) --> + <color name="tv_audio_recording_indicator_background">#FF3C4043</color> + <color name="tv_audio_recording_indicator_pulse">#4DFFFFFF</color> <color name="red">#FFCC0000</color> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 1dd5496b27f9..1053750a5538 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -990,12 +990,6 @@ <!-- Message shown when face authentication fails and the pin pad is visible. [CHAR LIMIT=60] --> <string name="keyguard_retry">Swipe up to try again</string> - <!-- Indication when device is slow charging due to misalignment on the dock. [CHAR LIMIT=60] --> - <string name="dock_alignment_slow_charging" product="default">Realign phone for faster charging</string> - - <!-- Indication when device is not charging due to bad placement on the dock. [CHAR LIMIT=60] --> - <string name="dock_alignment_not_charging" product="default">Realign phone to charge wirelessly</string> - <!-- Text on keyguard screen and in Quick Settings footer indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=60] --> <string name="do_disclosure_generic">This device is managed by your organization</string> @@ -2498,9 +2492,4 @@ <!-- Title of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=25] --> <string name="inattentive_sleep_warning_title">Standby</string> - <!-- Message of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=NONE] --> - <string name="inattentive_sleep_warning_message" product="tv">The Android TV device will soon turn off; press a button to keep it on.</string> - <!-- Message of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=NONE] --> - <string name="inattentive_sleep_warning_message" product="default">The device will soon turn off; press to keep it on.</string> - </resources> diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml index a9bdb71de039..6d61ff989cb1 100644 --- a/packages/SystemUI/res/values/strings_tv.xml +++ b/packages/SystemUI/res/values/strings_tv.xml @@ -31,4 +31,8 @@ <string name="pip_close">Close PIP</string> <!-- Button to move picture-in-picture (PIP) screen to the fullscreen in PIP menu [CHAR LIMIT=30] --> <string name="pip_fullscreen">Full screen</string> + + <!-- Title and subtitle for AudioRecordingIndicator --> + <string name="mic_active">Microphone Active</string> + <string name="app_accessed_mic">%1$s accessed your microphone</string> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 926d01685075..3ff824374aac 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -15,6 +15,7 @@ --> <resources xmlns:android="http://schemas.android.com/apk/res/android"> + <style name="BubbleOverflow" parent="@android:style/Theme.NoTitleBar"></style> <style name="ClearAllButtonDefaultMargins"> <item name="android:layout_marginStart">0dp</item> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java index eaf8d9b57398..35952f55ec1e 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java @@ -17,6 +17,7 @@ package com.android.systemui.shared.system; import android.app.ActivityManager; +import android.graphics.Bitmap; public class TaskDescriptionCompat { @@ -37,4 +38,12 @@ public class TaskDescriptionCompat { ? mTaskDescription.getBackgroundColor() : 0; } + + public static Bitmap getIcon(ActivityManager.TaskDescription desc, int userId) { + if (desc.getInMemoryIcon() != null) { + return desc.getInMemoryIcon(); + } + return ActivityManager.TaskDescription.loadTaskDescriptionIcon( + desc.getIconFilename(), userId); + } } diff --git a/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java b/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java index 72a403035294..4749addc7139 100644 --- a/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java @@ -280,6 +280,7 @@ public class SizeCompatModeActivityController extends SystemUI implements Comman R.layout.size_compat_mode_hint, null /* root */); PopupWindow popupWindow = new PopupWindow(popupView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + popupWindow.setWindowLayoutType(mWinParams.type); popupWindow.setElevation(getResources().getDimension(R.dimen.bubble_elevation)); popupWindow.setAnimationStyle(android.R.style.Animation_InputMethod); popupWindow.setClippingEnabled(false); diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt index adb288a9ce82..5cc70bc27c2a 100644 --- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt +++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt @@ -46,7 +46,7 @@ private const val MSG_ADD_RECEIVER = 0 private const val MSG_REMOVE_RECEIVER = 1 private const val MSG_REMOVE_RECEIVER_FOR_USER = 2 private const val TAG = "BroadcastDispatcher" -private const val DEBUG = false +private const val DEBUG = true /** * SystemUI master Broadcast Dispatcher. @@ -147,7 +147,13 @@ open class BroadcastDispatcher @Inject constructor ( when (msg.what) { MSG_ADD_RECEIVER -> { val data = msg.obj as ReceiverData - val userId = data.user.identifier + // If the receiver asked to be registered under the current user, we register + // under the actual current user. + val userId = if (data.user.identifier == UserHandle.USER_CURRENT) { + context.userId + } else { + data.user.identifier + } if (userId < UserHandle.USER_ALL) { if (DEBUG) Log.w(TAG, "Register receiver for invalid user: $userId") return diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java index f3a7ca9c0a75..7934e10c8605 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java @@ -297,7 +297,9 @@ class Bubble { * Whether the bubble for this notification should show a dot indicating updated content. */ boolean showDot() { - return mShowBubbleUpdateDot && !mEntry.shouldSuppressNotificationDot(); + return mShowBubbleUpdateDot + && !mEntry.shouldSuppressNotificationDot() + && !shouldSuppressNotification(); } /** @@ -305,6 +307,7 @@ class Bubble { */ boolean showFlyout() { return !mSuppressFlyout && !mEntry.shouldSuppressPeek() + && !shouldSuppressNotification() && !mEntry.shouldSuppressNotificationList(); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index dbb193669083..b5622432f919 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -44,13 +44,19 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.UserIdInt; import android.app.ActivityManager.RunningTaskInfo; +import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.RemoteInput; import android.content.Context; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.content.pm.ShortcutManager; import android.content.res.Configuration; import android.graphics.Rect; +import android.net.Uri; +import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; import android.service.notification.NotificationListenerService.RankingMap; @@ -69,6 +75,7 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.util.ScreenshotHelper; import com.android.systemui.R; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -86,6 +93,7 @@ import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.ZenModeController; import java.io.FileDescriptor; @@ -93,8 +101,10 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Singleton; @@ -138,6 +148,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi @Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer; private final NotificationGroupManager mNotificationGroupManager; private final Lazy<ShadeController> mShadeController; + private final RemoteInputUriController mRemoteInputUriController; + private Handler mHandler = new Handler() {}; private BubbleData mBubbleData; @Nullable private BubbleStackView mStackView; @@ -155,6 +167,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi private final StatusBarWindowController mStatusBarWindowController; private final ZenModeController mZenModeController; private StatusBarStateListener mStatusBarStateListener; + private final ScreenshotHelper mScreenshotHelper; + private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; private IStatusBarService mBarService; @@ -192,6 +206,16 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } /** + * Listener for handling bubble screenshot events. + */ + public interface BubbleScreenshotListener { + /** + * Called to trigger taking a screenshot and sending the result to a bubble. + */ + void onBubbleScreenshot(Bubble bubble); + } + + /** * Listens for the current state of the status bar and updates the visibility state * of bubbles as needed. */ @@ -226,10 +250,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager, NotificationGroupManager groupManager, - NotificationEntryManager entryManager) { + NotificationEntryManager entryManager, + RemoteInputUriController remoteInputUriController) { this(context, statusBarWindowController, statusBarStateController, shadeController, data, null /* synchronizer */, configurationController, interruptionStateProvider, - zenModeController, notifUserManager, groupManager, entryManager); + zenModeController, notifUserManager, groupManager, entryManager, + remoteInputUriController); } public BubbleController(Context context, @@ -243,11 +269,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager, NotificationGroupManager groupManager, - NotificationEntryManager entryManager) { + NotificationEntryManager entryManager, + RemoteInputUriController remoteInputUriController) { mContext = context; mNotificationInterruptionStateProvider = interruptionStateProvider; mNotifUserManager = notifUserManager; mZenModeController = zenModeController; + mRemoteInputUriController = remoteInputUriController; mZenModeController.addCallback(new ZenModeController.Callback() { @Override public void onZenChanged(int zen) { @@ -320,6 +348,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi }); mUserCreatedBubbles = new HashSet<>(); + + mScreenshotHelper = new ScreenshotHelper(context); } /** @@ -337,6 +367,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (mExpandListener != null) { mStackView.setExpandListener(mExpandListener); } + if (mBubbleScreenshotListener != null) { + mStackView.setBubbleScreenshotListener(mBubbleScreenshotListener); + } } } @@ -845,12 +878,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (DEBUG_BUBBLE_CONTROLLER) { Log.d(TAG, "[BubbleData]"); - Log.d(TAG, formatBubblesString(mBubbleData.getBubbles(), + Log.d(TAG, BubbleDebugConfig.formatBubblesString(mBubbleData.getBubbles(), mBubbleData.getSelectedBubble())); if (mStackView != null) { Log.d(TAG, "[BubbleStackView]"); - Log.d(TAG, formatBubblesString(mStackView.getBubblesOnScreen(), + Log.d(TAG, BubbleDebugConfig.formatBubblesString(mStackView.getBubblesOnScreen(), mStackView.getExpandedBubble())); } } @@ -939,23 +972,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi pw.println(); } - static String formatBubblesString(List<Bubble> bubbles, Bubble selected) { - StringBuilder sb = new StringBuilder(); - for (Bubble bubble : bubbles) { - if (bubble == null) { - sb.append(" <null> !!!!!\n"); - } else { - boolean isSelected = (bubble == selected); - sb.append(String.format("%s Bubble{act=%12d, ongoing=%d, key=%s}\n", - ((isSelected) ? "->" : " "), - bubble.getLastActivity(), - (bubble.isOngoing() ? 1 : 0), - bubble.getKey())); - } - } - return sb.toString(); - } - /** * This task stack listener is responsible for responding to tasks moved to the front * which are on the default (main) display. When this happens, expanded bubbles must be @@ -1058,4 +1074,71 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } } } + + // TODO: Copied from RemoteInputView. Consolidate RemoteInput intent logic. + private Intent prepareRemoteInputFromData(String contentType, Uri data, + RemoteInput remoteInput, NotificationEntry entry) { + HashMap<String, Uri> results = new HashMap<>(); + results.put(contentType, data); + mRemoteInputUriController.grantInlineReplyUriPermission(entry.getSbn(), data); + Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + RemoteInput.addDataResultToIntent(remoteInput, fillInIntent, results); + + return fillInIntent; + } + + // TODO: Copied from RemoteInputView. Consolidate RemoteInput intent logic. + private void sendRemoteInput(Intent intent, NotificationEntry entry, + PendingIntent pendingIntent) { + // Tell ShortcutManager that this package has been "activated". ShortcutManager + // will reset the throttling for this package. + // Strictly speaking, the intent receiver may be different from the notification publisher, + // but that's an edge case, and also because we can't always know which package will receive + // an intent, so we just reset for the publisher. + mContext.getSystemService(ShortcutManager.class).onApplicationActive( + entry.getSbn().getPackageName(), + entry.getSbn().getUser().getIdentifier()); + + try { + pendingIntent.send(mContext, 0, intent); + } catch (PendingIntent.CanceledException e) { + Log.i(TAG, "Unable to send remote input result", e); + } + } + + private void sendScreenshotToBubble(Bubble bubble) { + // delay allows the bubble menu to disappear before the screenshot + // done here because we already have a Handler to delay with. + // TODO: Hide bubble + menu UI from screenshots entirely instead of just delaying. + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + mScreenshotHelper.takeScreenshot( + android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN, + true /* hasStatus */, + true /* hasNav */, + mHandler, + new Consumer<Uri>() { + @Override + public void accept(Uri uri) { + if (uri != null) { + NotificationEntry entry = bubble.getEntry(); + Pair<RemoteInput, Notification.Action> pair = entry.getSbn() + .getNotification().findRemoteInputActionPair(false); + RemoteInput remoteInput = pair.first; + Notification.Action action = pair.second; + Intent dataIntent = prepareRemoteInputFromData("image/png", uri, + remoteInput, entry); + sendRemoteInput(dataIntent, entry, action.actionIntent); + mBubbleData.setSelectedBubble(bubble); + mBubbleData.setExpanded(true); + } + } + }); + } + }, 200); + } + + private final BubbleScreenshotListener mBubbleScreenshotListener = + bubble -> sendScreenshotToBubble(bubble); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java index 034bff345d71..b7df5baa4cf1 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java @@ -48,6 +48,7 @@ import java.util.Objects; import javax.inject.Inject; import javax.inject.Singleton; +import com.android.systemui.R; /** * Keeps track of active bubbles. @@ -57,8 +58,6 @@ public class BubbleData { private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleData" : TAG_BUBBLES; - private static final int MAX_BUBBLES = 5; - private static final Comparator<Bubble> BUBBLES_BY_SORT_KEY_DESCENDING = Comparator.comparing(BubbleData::sortKey).reversed(); @@ -115,6 +114,7 @@ public class BubbleData { private final List<Bubble> mBubbles; private Bubble mSelectedBubble; private boolean mExpanded; + private final int mMaxBubbles; // State tracked during an operation -- keeps track of what listener events to dispatch. private Update mStateChange; @@ -144,6 +144,7 @@ public class BubbleData { mContext = context; mBubbles = new ArrayList<>(); mStateChange = new Update(mBubbles); + mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered); } public boolean hasBubbles() { @@ -329,7 +330,7 @@ public class BubbleData { } private void trim() { - if (mBubbles.size() > MAX_BUBBLES) { + if (mBubbles.size() > mMaxBubbles) { mBubbles.stream() // sort oldest first (ascending lastActivity) .sorted(Comparator.comparingLong(Bubble::getLastActivity)) diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java index a912eccd4d5e..319066221600 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java @@ -16,6 +16,8 @@ package com.android.systemui.bubbles; +import java.util.List; + /** * Common class for the various debug {@link android.util.Log} output configuration in the Bubbles * package. @@ -38,5 +40,23 @@ public class BubbleDebugConfig { static final boolean DEBUG_BUBBLE_STACK_VIEW = false; static final boolean DEBUG_BUBBLE_EXPANDED_VIEW = false; static final boolean DEBUG_EXPERIMENTS = true; + static final boolean DEBUG_OVERFLOW = false; + static String formatBubblesString(List<Bubble> bubbles, Bubble selected) { + StringBuilder sb = new StringBuilder(); + for (Bubble bubble : bubbles) { + if (bubble == null) { + sb.append(" <null> !!!!!\n"); + } else { + boolean isSelected = (selected != null && bubble == selected); + String arrow = isSelected ? "=>" : " "; + sb.append(String.format("%s Bubble{act=%12d, ongoing=%d, key=%s}\n", + arrow, + bubble.getLastActivity(), + (bubble.isOngoing() ? 1 : 0), + bubble.getKey())); + } + } + return sb.toString(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index efc955d9bca4..63d036d6362d 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -275,17 +275,15 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList } void applyThemeAttrs() { - TypedArray ta = getContext().obtainStyledAttributes(R.styleable.BubbleExpandedView); - int bgColor = ta.getColor( - R.styleable.BubbleExpandedView_android_colorBackgroundFloating, Color.WHITE); - float cornerRadius = ta.getDimension( - R.styleable.BubbleExpandedView_android_dialogCornerRadius, 0); + final TypedArray ta = mContext.obtainStyledAttributes( + new int[] { + android.R.attr.colorBackgroundFloating, + android.R.attr.dialogCornerRadius}); + int bgColor = ta.getColor(0, Color.WHITE); + float cornerRadius = ta.getDimensionPixelSize(1, 0); ta.recycle(); - // Update triangle color. mPointerDrawable.setTint(bgColor); - - // Update ActivityView cornerRadius if (ScreenDecorationsUtils.supportsRoundedCornersOnWindows(mContext.getResources())) { mActivityView.setCornerRadius(cornerRadius); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java index e138d9387ca6..41879855275f 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java @@ -68,6 +68,9 @@ public class BubbleExperimentConfig { private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps"; + private static final String ALLOW_BUBBLE_MENU = "allow_bubble_screenshot_menu"; + private static final boolean ALLOW_BUBBLE_MENU_DEFAULT = false; + /** * When true, if a notification has the information necessary to bubble (i.e. valid * contentIntent and an icon or image), then a {@link android.app.Notification.BubbleMetadata} @@ -123,6 +126,16 @@ public class BubbleExperimentConfig { } /** + * When true, show a menu when a bubble is long-pressed, which will allow the user to take + * actions on that bubble. + */ + static boolean allowBubbleScreenshotMenu(Context context) { + return Settings.Secure.getInt(context.getContentResolver(), + ALLOW_BUBBLE_MENU, + ALLOW_BUBBLE_MENU_DEFAULT ? 1 : 0) != 0; + } + + /** * If {@link #allowAnyNotifToBubble(Context)} is true, this method creates and adds * {@link android.app.Notification.BubbleMetadata} to the notification entry as long as * the notification has necessary info for BubbleMetadata. @@ -211,7 +224,11 @@ public class BubbleExperimentConfig { // Use the icon of the person if available List<Person> personList = getPeopleFromNotification(entry); if (personList.size() > 0) { - icon = personList.get(0).getIcon(); + final Person person = personList.get(0); + + if (person != null) { + icon = person.getIcon(); + } } if (icon == null) { icon = notification.getLargeIcon() != null diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java new file mode 100644 index 000000000000..e8eb72e8392f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.bubbles; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.android.systemui.R; + +/** + * Menu which allows users to take actions on bubbles, ex. screenshots. + */ +public class BubbleMenuView extends FrameLayout { + private FrameLayout mMenu; + private boolean mShowing = false; + + public BubbleMenuView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public BubbleMenuView(Context context) { + super(context); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mMenu = findViewById(R.id.bubble_menu_view); + ImageView icon = findViewById(com.android.internal.R.id.icon); + icon.setImageDrawable(mContext.getDrawable(com.android.internal.R.drawable.ic_screenshot)); + } + + /** + * Get the bubble menu view. + */ + public View getMenuView() { + return mMenu; + } + + /** + * Checks whether the bubble menu is currently displayed. + */ + public boolean isShowing() { + return mShowing; + } + + /** + * Show the bubble menu at the specified position on the screen. + */ + public void show(float x, float y) { + mShowing = true; + this.setVisibility(VISIBLE); + mMenu.setTranslationX(x); + mMenu.setTranslationY(y); + } + + /** + * Hide the bubble menu. + */ + public void hide() { + mShowing = false; + this.setVisibility(GONE); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java new file mode 100644 index 000000000000..018b6318575a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java @@ -0,0 +1,69 @@ +package com.android.systemui.bubbles; + +import android.app.Activity; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.os.Bundle; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.android.systemui.R; + +/** + * Activity for showing aged out bubbles. + * Must be public to be accessible to androidx...AppComponentFactory + */ +public class BubbleOverflowActivity extends Activity { + private RecyclerView mRecyclerView; + private int mMaxBubbles; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.bubble_overflow_activity); + setBackgroundColor(); + + mMaxBubbles = getResources().getInteger(R.integer.bubbles_max_rendered); + mRecyclerView = findViewById(R.id.bubble_overflow_recycler); + mRecyclerView.setLayoutManager( + new GridLayoutManager(getApplicationContext(), /* numberOfColumns */ mMaxBubbles)); + } + + void setBackgroundColor() { + final TypedArray ta = getApplicationContext().obtainStyledAttributes( + new int[] {android.R.attr.colorBackgroundFloating}); + int bgColor = ta.getColor(0, Color.WHITE); + ta.recycle(); + findViewById(android.R.id.content).setBackgroundColor(bgColor); + } + + @Override + public void onStart() { + super.onStart(); + } + + @Override + public void onRestart() { + super.onRestart(); + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + } + + @Override + public void onStop() { + super.onStop(); + } + + public void onDestroy() { + super.onStop(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 29de2f049690..29a4bb1fca84 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -110,6 +110,7 @@ public class BubbleStackView extends FrameLayout { /** How long to wait, in milliseconds, before hiding the flyout. */ @VisibleForTesting static final int FLYOUT_HIDE_AFTER = 5000; + private BubbleController.BubbleScreenshotListener mBubbleScreenshotListener; /** * Interface to synchronize {@link View} state and the screen. @@ -163,6 +164,7 @@ public class BubbleStackView extends FrameLayout { private ExpandedAnimationController mExpandedAnimationController; private FrameLayout mExpandedViewContainer; + @Nullable private BubbleMenuView mBubbleMenuView; private BubbleFlyoutView mFlyout; /** Runnable that fades out the flyout and then sets it to GONE. */ @@ -194,6 +196,7 @@ public class BubbleStackView extends FrameLayout { private int mPointerHeight; private int mStatusBarHeight; private int mImeOffset; + private int mBubbleMenuOffset = 252; private BubbleIconFactory mBubbleIconFactory; private Bubble mExpandedBubble; private boolean mIsExpanded; @@ -492,6 +495,9 @@ public class BubbleStackView extends FrameLayout { mDesaturateAndDarkenPaint.setColorFilter(new ColorMatrixColorFilter(animatedMatrix)); mDesaturateAndDarkenTargetView.setLayerPaint(mDesaturateAndDarkenPaint); }); + + mInflater.inflate(R.layout.bubble_menu_view, this); + mBubbleMenuView = findViewById(R.id.bubble_menu_container); } private void setUpFlyout() { @@ -683,6 +689,13 @@ public class BubbleStackView extends FrameLayout { } /** + * Sets the screenshot listener. + */ + public void setBubbleScreenshotListener(BubbleController.BubbleScreenshotListener listener) { + mBubbleScreenshotListener = listener; + } + + /** * Whether the stack of bubbles is expanded or not. */ public boolean isExpanded() { @@ -870,6 +883,12 @@ public class BubbleStackView extends FrameLayout { public View getTargetView(MotionEvent event) { float x = event.getRawX(); float y = event.getRawY(); + if (mBubbleMenuView.isShowing()) { + if (isIntersecting(mBubbleMenuView.getMenuView(), x, y)) { + return mBubbleMenuView; + } + return null; + } if (mIsExpanded) { if (isIntersecting(mBubbleContainer, x, y)) { // Could be tapping or dragging a bubble while expanded @@ -1074,6 +1093,7 @@ public class BubbleStackView extends FrameLayout { return; } + hideBubbleMenu(); mStackAnimationController.cancelStackPositionAnimations(); mBubbleContainer.setActiveController(mStackAnimationController); hideFlyoutImmediate(); @@ -1473,6 +1493,11 @@ public class BubbleStackView extends FrameLayout { @Override public void getBoundsOnScreen(Rect outRect) { + // If the bubble menu is open, the entire screen should capture touch events. + if (mBubbleMenuView.isShowing()) { + outRect.set(0, 0, getWidth(), getHeight()); + return; + } if (!mIsExpanded) { if (mBubbleContainer.getChildCount() > 0) { mBubbleContainer.getChildAt(0).getBoundsOnScreen(outRect); @@ -1700,4 +1725,43 @@ public class BubbleStackView extends FrameLayout { } return bubbles; } + + /** + * Show the bubble menu, positioned relative to the stack. + */ + public void showBubbleMenu() { + PointF currentPos = mStackAnimationController.getStackPosition(); + float yPos = currentPos.y; + float xPos = currentPos.x; + if (mStackAnimationController.isStackOnLeftSide()) { + xPos += mBubbleSize; + } else { + //TODO: Use the width of the menu instead of this fixed offset. Offset used for now + // because menu width isn't correct the first time the menu is shown. + xPos -= mBubbleMenuOffset; + } + + mBubbleMenuView.show(xPos, yPos); + } + + /** + * Hide the bubble menu. + */ + public void hideBubbleMenu() { + mBubbleMenuView.hide(); + } + + /** + * Determines whether the bubble menu is currently showing. + */ + public boolean isShowingBubbleMenu() { + return mBubbleMenuView.isShowing(); + } + + /** + * Take a screenshot and send it to the specified bubble. + */ + public void sendScreenshotToBubble(Bubble bubble) { + mBubbleScreenshotListener.onBubbleScreenshot(bubble); + } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java index 44e013a34f54..b1d205c79c99 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java @@ -57,6 +57,7 @@ class BubbleTouchHandler implements View.OnTouchListener { private final PointF mViewPositionOnTouchDown = new PointF(); private final BubbleStackView mStack; private final BubbleData mBubbleData; + private final Context mContext; private BubbleController mController = Dependency.get(BubbleController.class); @@ -75,6 +76,7 @@ class BubbleTouchHandler implements View.OnTouchListener { mTouchSlopSquared = touchSlop * touchSlop; mBubbleData = bubbleData; mStack = stackView; + mContext = context; } @Override @@ -91,15 +93,24 @@ class BubbleTouchHandler implements View.OnTouchListener { // anything, collapse the stack. if (action == MotionEvent.ACTION_OUTSIDE || mTouchedView == null) { mBubbleData.setExpanded(false); + mStack.hideBubbleMenu(); resetForNextGesture(); return false; } + if (mTouchedView instanceof BubbleMenuView) { + mStack.hideBubbleMenu(); + resetForNextGesture(); + mStack.sendScreenshotToBubble(mBubbleData.getSelectedBubble()); + return false; + } + if (!(mTouchedView instanceof BadgedImageView) && !(mTouchedView instanceof BubbleStackView) && !(mTouchedView instanceof BubbleFlyoutView)) { // Not touching anything touchable, but we shouldn't collapse (e.g. touching edge // of expanded view). + mStack.hideBubbleMenu(); resetForNextGesture(); return false; } @@ -132,6 +143,10 @@ class BubbleTouchHandler implements View.OnTouchListener { break; case MotionEvent.ACTION_MOVE: + // block all further touch inputs once the menu is open + if (mStack.isShowingBubbleMenu()) { + return true; + } trackMovement(event); final float deltaX = rawX - mTouchDown.x; final float deltaY = rawY - mTouchDown.y; @@ -148,6 +163,13 @@ class BubbleTouchHandler implements View.OnTouchListener { } else { mStack.onBubbleDragged(mTouchedView, viewX, viewY); } + } else { + float touchTime = event.getEventTime() - event.getDownTime(); + if (touchTime > ViewConfiguration.getLongPressTimeout() && !mStack.isExpanded() + && BubbleExperimentConfig.allowBubbleScreenshotMenu(mContext)) { + mStack.showBubbleMenu(); + return true; + } } final boolean currentlyInDismissTarget = mStack.isInDismissTarget(event); @@ -171,6 +193,10 @@ class BubbleTouchHandler implements View.OnTouchListener { break; case MotionEvent.ACTION_UP: + if (mStack.isShowingBubbleMenu()) { + resetForNextGesture(); + return true; + } trackMovement(event); mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000); final float velX = mVelocityTracker.getXVelocity(); @@ -261,7 +287,6 @@ class BubbleTouchHandler implements View.OnTouchListener { mVelocityTracker.recycle(); mVelocityTracker = null; } - mTouchedView = null; mMovedEnough = false; mInDismissTarget = false; diff --git a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java index f094cb909cf2..0f71d22b218f 100644 --- a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java @@ -47,7 +47,8 @@ public class SysuiLog implements Dumpable { private final Object mDataLock = new Object(); private final String mId; private final int mMaxLogs; - private boolean mEnabled; + protected boolean mEnabled; + protected boolean mLogToLogcatEnabled; @VisibleForTesting protected ArrayDeque<Event> mTimeline; @@ -62,14 +63,18 @@ public class SysuiLog implements Dumpable { */ public SysuiLog(DumpController dumpController, String id, int maxDebugLogs, int maxLogs) { this(dumpController, id, sDebuggable ? maxDebugLogs : maxLogs, - SystemProperties.getBoolean(SYSPROP_ENABLED_PREFIX + id, DEFAULT_ENABLED)); + SystemProperties.getBoolean(SYSPROP_ENABLED_PREFIX + id, DEFAULT_ENABLED), + SystemProperties.getBoolean(SYSPROP_LOGCAT_ENABLED_PREFIX + id, + DEFAULT_LOGCAT_ENABLED)); } @VisibleForTesting - protected SysuiLog(DumpController dumpController, String id, int maxLogs, boolean enabled) { + protected SysuiLog(DumpController dumpController, String id, int maxLogs, boolean enabled, + boolean logcatEnabled) { mId = id; mMaxLogs = maxLogs; mEnabled = enabled; + mLogToLogcatEnabled = logcatEnabled; mTimeline = mEnabled ? new ArrayDeque<>(mMaxLogs) : null; dumpController.registerDumpable(mId, this); } @@ -96,7 +101,7 @@ public class SysuiLog implements Dumpable { mTimeline.add(event); } - if (LOG_TO_LOGCAT_ENABLED) { + if (mLogToLogcatEnabled) { final String strEvent = eventToString(event); switch (event.getLogLevel()) { case Event.VERBOSE: @@ -162,9 +167,10 @@ public class SysuiLog implements Dumpable { } private static boolean sDebuggable = Build.IS_DEBUGGABLE; - private static final String SYSPROP_ENABLED_PREFIX = "sysui.log.enabled."; - private static final boolean LOG_TO_LOGCAT_ENABLED = sDebuggable; + private static final String SYSPROP_ENABLED_PREFIX = "persist.sysui.log.enabled."; + private static final String SYSPROP_LOGCAT_ENABLED_PREFIX = "persist.sysui.log.enabled.logcat."; private static final boolean DEFAULT_ENABLED = sDebuggable; + private static final boolean DEFAULT_LOGCAT_ENABLED = false; private static final int DEFAULT_MAX_DEBUG_LOGS = 100; private static final int DEFAULT_MAX_LOGS = 50; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java index 5bb882e2355f..d40e25064352 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java @@ -250,6 +250,14 @@ public class QuickQSMediaPlayer { return (state.getState() == PlaybackState.STATE_PLAYING); } + /** + * Check whether this player has an attached media session. + * @return whether there is a controller with a current media session. + */ + public boolean hasMediaSession() { + return mController != null && mController.getPlaybackState() != null; + } + private void addAlbumArtBackground(MediaMetadata metadata, int bgColor) { Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index d377f1c793a9..feb10a2e9a6e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -57,6 +57,12 @@ public class QuickQSPanel extends QSPanel { private int mMaxTiles; protected QSPanel mFullPanel; private QuickQSMediaPlayer mMediaPlayer; + private boolean mUsingMediaPlayer; + private LinearLayout mHorizontalLinearLayout; + + // Only used with media + private QSTileLayout mMediaTileLayout; + private QSTileLayout mRegularTileLayout; @Inject public QuickQSPanel(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, @@ -72,8 +78,9 @@ public class QuickQSPanel extends QSPanel { removeView((View) mTileLayout); } - if (Utils.useQsMediaPlayer(context)) { - LinearLayout mHorizontalLinearLayout = new LinearLayout(mContext); + mUsingMediaPlayer = Utils.useQsMediaPlayer(context); + if (mUsingMediaPlayer) { + mHorizontalLinearLayout = new LinearLayout(mContext); mHorizontalLinearLayout.setOrientation(LinearLayout.HORIZONTAL); mHorizontalLinearLayout.setClipChildren(false); mHorizontalLinearLayout.setClipToPadding(false); @@ -81,6 +88,8 @@ public class QuickQSPanel extends QSPanel { LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1); mTileLayout = new DoubleLineTileLayout(context); + mMediaTileLayout = mTileLayout; + mRegularTileLayout = new HeaderTileLayout(context); lp.setMarginEnd(10); lp.setMarginStart(0); mHorizontalLinearLayout.addView((View) mTileLayout, lp); @@ -95,6 +104,8 @@ public class QuickQSPanel extends QSPanel { mTileLayout.setListening(mListening); addView(mHorizontalLinearLayout, 0 /* Between brightness and footer */); + ((View) mRegularTileLayout).setVisibility(View.GONE); + addView((View) mRegularTileLayout, 0); super.setPadding(0, 0, 0, 0); } else { sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns); @@ -130,6 +141,8 @@ public class QuickQSPanel extends QSPanel { Dependency.get(TunerService.class).removeTunable(mNumTiles); } + + @Override protected String getDumpableTag() { return TAG; @@ -152,6 +165,42 @@ public class QuickQSPanel extends QSPanel { super.drawTile(r, state); } + boolean switchTileLayout() { + if (!mUsingMediaPlayer) return false; + if (mMediaPlayer.hasMediaSession() + && mHorizontalLinearLayout.getVisibility() == View.GONE) { + mHorizontalLinearLayout.setVisibility(View.VISIBLE); + ((View) mRegularTileLayout).setVisibility(View.GONE); + mTileLayout.setListening(false); + for (TileRecord record : mRecords) { + mTileLayout.removeTile(record); + record.tile.removeCallback(record.callback); + } + mTileLayout = mMediaTileLayout; + setTiles(mHost.getTiles()); + mTileLayout.setListening(mListening); + return true; + } else if (!mMediaPlayer.hasMediaSession() + && mHorizontalLinearLayout.getVisibility() == View.VISIBLE) { + mHorizontalLinearLayout.setVisibility(View.GONE); + ((View) mRegularTileLayout).setVisibility(View.VISIBLE); + mTileLayout.setListening(false); + for (TileRecord record : mRecords) { + mTileLayout.removeTile(record); + record.tile.removeCallback(record.callback); + } + mTileLayout = mRegularTileLayout; + setTiles(mHost.getTiles()); + mTileLayout.setListening(mListening); + return true; + } + return false; + } + + public boolean hasMediaPlayerSession() { + return mMediaPlayer.hasMediaSession(); + } + @Override public void setHost(QSTileHost host, QSCustomizer customizer) { super.setHost(host, customizer); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index e5cec878b63d..d4af1548af41 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -339,7 +339,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements if (mQsDisabled) { lp.height = resources.getDimensionPixelSize( com.android.internal.R.dimen.quick_qs_offset_height); - } else if (useQsMediaPlayer(mContext)) { + } else if (useQsMediaPlayer(mContext) && mHeaderQsPanel.hasMediaPlayerSession()) { lp.height = Math.max(getMinimumHeight(), resources.getDimensionPixelSize( com.android.internal.R.dimen.quick_qs_total_height_with_media)); @@ -405,6 +405,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements mHeaderTextContainerView.setVisibility(INVISIBLE); } } + if (expansionFraction < 1 && expansionFraction > 0.99) { + if (mHeaderQsPanel.switchTileLayout()) { + updateResources(); + } + } } public void disable(int state1, int state2, boolean animate) { @@ -453,6 +458,9 @@ public class QuickStatusBarHeader extends RelativeLayout implements return; } mHeaderQsPanel.setListening(listening); + if (mHeaderQsPanel.switchTileLayout()) { + updateResources(); + } mListening = listening; if (listening) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java index 9fe9703e4181..d79e38332af5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java @@ -92,7 +92,7 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements boolean nightMode = (mContext.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; - if (isAuto) { + if (isAuto && !powerSave) { state.secondaryLabel = mContext.getResources().getString(nightMode ? R.string.quick_settings_dark_mode_secondary_label_until_sunrise : R.string.quick_settings_dark_mode_secondary_label_on_at_sunset); @@ -123,7 +123,7 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements @Override public Intent getLongClickIntent() { - return new Intent(Settings.ACTION_DISPLAY_SETTINGS); + return new Intent(Settings.ACTION_DARK_THEME_SETTINGS); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index d3a9c2c3c87d..246b0f0e19ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -61,7 +61,6 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.LockscreenWallpaper; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ScrimState; -import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -105,9 +104,6 @@ public class NotificationMediaManager implements Dumpable { private final NotificationEntryManager mEntryManager; - // Late binding, also @Nullable due to being in com.android.systemui.statusbar.phone package - @Nullable - private Lazy<ShadeController> mShadeController; @Nullable private Lazy<StatusBarWindowController> mStatusBarWindowController; @@ -183,7 +179,6 @@ public class NotificationMediaManager implements Dumpable { @Inject public NotificationMediaManager( Context context, - Lazy<ShadeController> shadeController, Lazy<StatusBar> statusBarLazy, Lazy<StatusBarWindowController> statusBarWindowController, NotificationEntryManager notificationEntryManager, @@ -193,11 +188,10 @@ public class NotificationMediaManager implements Dumpable { mMediaArtworkProcessor = mediaArtworkProcessor; mKeyguardBypassController = keyguardBypassController; mMediaListeners = new ArrayList<>(); - mMediaSessionManager - = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE); // TODO: use MediaSessionManager.SessionListener to hook us up to future updates // in session state - mShadeController = shadeController; + mMediaSessionManager = (MediaSessionManager) mContext.getSystemService( + Context.MEDIA_SESSION_SERVICE); // TODO: use KeyguardStateController#isOccluded to remove this dependency mStatusBarLazy = statusBarLazy; mStatusBarWindowController = statusBarWindowController; @@ -603,9 +597,7 @@ public class NotificationMediaManager implements Dumpable { if (DEBUG_MEDIA) { Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork"); } - ShadeController shadeController = mShadeController.get(); - boolean cannotAnimateDoze = shadeController != null - && shadeController.isDozing() + boolean cannotAnimateDoze = mStatusBarStateController.isDozing() && !ScrimState.AOD.getAnimateChange(); boolean needsBypassFading = mKeyguardStateController.isBypassFadingAnimation(); if (((mBiometricUnlockController != null && mBiometricUnlockController.getMode() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index c556bc0b39d1..f6f3ac1b5aaf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -58,7 +58,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.phone.ShadeController; +import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.RemoteInputView; @@ -116,7 +116,7 @@ public class NotificationRemoteInputManager implements Dumpable { private final NotificationEntryManager mEntryManager; private final Handler mMainHandler; - private final Lazy<ShadeController> mShadeController; + private final Lazy<StatusBar> mStatusBarLazy; protected final Context mContext; private final UserManager mUserManager; @@ -136,7 +136,7 @@ public class NotificationRemoteInputManager implements Dumpable { @Override public boolean onClickHandler( View view, PendingIntent pendingIntent, RemoteViews.RemoteResponse response) { - mShadeController.get().wakeUpIfDozing(SystemClock.uptimeMillis(), view, + mStatusBarLazy.get().wakeUpIfDozing(SystemClock.uptimeMillis(), view, "NOTIFICATION_CLICK"); if (handleRemoteInput(view, pendingIntent)) { @@ -261,7 +261,7 @@ public class NotificationRemoteInputManager implements Dumpable { NotificationLockscreenUserManager lockscreenUserManager, SmartReplyController smartReplyController, NotificationEntryManager notificationEntryManager, - Lazy<ShadeController> shadeController, + Lazy<StatusBar> statusBarLazy, StatusBarStateController statusBarStateController, @MainHandler Handler mainHandler, RemoteInputUriController remoteInputUriController) { @@ -269,7 +269,7 @@ public class NotificationRemoteInputManager implements Dumpable { mLockscreenUserManager = lockscreenUserManager; mSmartReplyController = smartReplyController; mEntryManager = notificationEntryManager; - mShadeController = shadeController; + mStatusBarLazy = statusBarLazy; mMainHandler = mainHandler; mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt index e516af590e34..88f148b00cdc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt @@ -211,7 +211,7 @@ constructor( setUserLocked(mStartingChild!!, false) mStartingChild = null } - if (shadeController.isDozing) { + if (statusBarStateController.isDozing) { isWakingToShadeLocked = true wakeUpCoordinator.willWakeUp = true mPowerManager!!.wakeUp(SystemClock.uptimeMillis(), WAKE_REASON_GESTURE, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java index 65f3fa94374b..31b7cb0fb5a0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java @@ -24,18 +24,16 @@ import android.service.notification.StatusBarNotification; import android.util.Log; import com.android.internal.statusbar.NotificationVisibility; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; -import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.HeadsUpManager; import javax.inject.Inject; import javax.inject.Singleton; -import dagger.Lazy; - /** Handles heads-up and pulsing behavior driven by notification changes. */ @Singleton public class NotificationAlertingManager { @@ -44,7 +42,7 @@ public class NotificationAlertingManager { private final NotificationRemoteInputManager mRemoteInputManager; private final VisualStabilityManager mVisualStabilityManager; - private final Lazy<ShadeController> mShadeController; + private final StatusBarStateController mStatusBarStateController; private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; private final NotificationListener mNotificationListener; @@ -55,12 +53,12 @@ public class NotificationAlertingManager { NotificationEntryManager notificationEntryManager, NotificationRemoteInputManager remoteInputManager, VisualStabilityManager visualStabilityManager, - Lazy<ShadeController> shadeController, + StatusBarStateController statusBarStateController, NotificationInterruptionStateProvider notificationInterruptionStateProvider, NotificationListener notificationListener) { mRemoteInputManager = remoteInputManager; mVisualStabilityManager = visualStabilityManager; - mShadeController = shadeController; + mStatusBarStateController = statusBarStateController; mNotificationInterruptionStateProvider = notificationInterruptionStateProvider; mNotificationListener = notificationListener; @@ -102,7 +100,7 @@ public class NotificationAlertingManager { // If it does and we no longer need to heads up, we should free the view. if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) { mHeadsUpManager.showNotification(entry); - if (!mShadeController.get().isDozing()) { + if (!mStatusBarStateController.isDozing()) { // Mark as seen immediately setNotificationShown(entry.getSbn()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java index b5c664116944..c8b34f1f5b27 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java @@ -24,7 +24,9 @@ import android.view.View; import com.android.systemui.DejankUtils; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.phone.ShadeController; +import com.android.systemui.statusbar.phone.StatusBar; + +import java.util.Optional; /** * Click handler for generic clicks on notifications. Clicks on specific areas (expansion caret, @@ -33,14 +35,14 @@ import com.android.systemui.statusbar.phone.ShadeController; public final class NotificationClicker implements View.OnClickListener { private static final String TAG = "NotificationClicker"; - private final ShadeController mShadeController; + private final Optional<StatusBar> mStatusBar; private final BubbleController mBubbleController; private final NotificationActivityStarter mNotificationActivityStarter; - public NotificationClicker(ShadeController shadeController, + public NotificationClicker(Optional<StatusBar> statusBar, BubbleController bubbleController, NotificationActivityStarter notificationActivityStarter) { - mShadeController = shadeController; + mStatusBar = statusBar; mBubbleController = bubbleController; mNotificationActivityStarter = notificationActivityStarter; } @@ -52,7 +54,8 @@ public final class NotificationClicker implements View.OnClickListener { return; } - mShadeController.wakeUpIfDozing(SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK"); + mStatusBar.ifPresent(statusBar -> statusBar.wakeUpIfDozing( + SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK")); final ExpandableNotificationRow row = (ExpandableNotificationRow) v; final StatusBarNotification sbn = row.getEntry().getSbn(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java index b61c1ef50cae..6c61923332ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java @@ -27,6 +27,7 @@ import android.service.notification.StatusBarNotification; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.ForegroundServiceController; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -45,6 +46,7 @@ public class NotificationFilter { private final NotificationGroupManager mGroupManager = Dependency.get( NotificationGroupManager.class); + private final StatusBarStateController mStatusBarStateController; private NotificationEntryManager.KeyguardEnvironment mEnvironment; private ShadeController mShadeController; @@ -52,7 +54,9 @@ public class NotificationFilter { private NotificationLockscreenUserManager mUserManager; @Inject - public NotificationFilter() {} + public NotificationFilter(StatusBarStateController statusBarStateController) { + mStatusBarStateController = statusBarStateController; + } private NotificationEntryManager.KeyguardEnvironment getEnvironment() { if (mEnvironment == null) { @@ -104,11 +108,11 @@ public class NotificationFilter { return true; } - if (getShadeController().isDozing() && entry.shouldSuppressAmbient()) { + if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) { return true; } - if (!getShadeController().isDozing() && entry.shouldSuppressNotificationList()) { + if (!mStatusBarStateController.isDozing() && entry.shouldSuppressNotificationList()) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 35407c6df690..ed2fb0fdcb1a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -2989,7 +2989,7 @@ public class NotificationPanelView extends PanelView implements return true; case StatusBarState.SHADE_LOCKED: if (!mQsExpanded) { - mShadeController.goToKeyguard(); + mStatusBarStateController.setState(StatusBarState.KEYGUARD); } return true; case StatusBarState.SHADE: diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java index b31ce6afc281..deea3f17aad0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java @@ -14,11 +14,9 @@ package com.android.systemui.statusbar.phone; -import android.annotation.NonNull; import android.view.View; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; /** * {@link ShadeController} is an abstraction of the work that used to be hard-coded in @@ -30,14 +28,6 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi public interface ShadeController { /** - * Shows the keyguard bouncer - the password challenge on the lock screen - * - * @param scrimmed true when the bouncer should show scrimmed, false when the user will be - * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)} - */ - void showBouncer(boolean scrimmed); - - /** * Make our window larger and the panel expanded */ void instantExpandNotificationsPanel(); @@ -71,12 +61,6 @@ public interface ShadeController { void addPostCollapseAction(Runnable action); /** - * Ask shade controller to set the state to {@link StatusBarState#KEYGUARD}, but only from - * {@link StatusBarState#SHADE_LOCKED} - */ - void goToKeyguard(); - - /** * Notify the shade controller that the current user changed * * @param newUserId userId of the new user @@ -84,22 +68,6 @@ public interface ShadeController { void setLockscreenUser(int newUserId); /** - * Dozing is when the screen is in AOD or asleep - * - * @return true if we are dozing - */ - boolean isDozing(); - - /** - * Ask the display to wake up if currently dozing, else do nothing - * - * @param time when to wake up - * @param view the view requesting the wakeup - * @param why the reason for the wake up - */ - void wakeUpIfDozing(long time, View view, @NonNull String why); - - /** * If secure with redaction: Show bouncer, go to unlocked shade. * * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p> @@ -109,11 +77,6 @@ public interface ShadeController { void goToLockedShade(View startingChild); /** - * Adds a {@param runnable} to be executed after Keyguard is gone. - */ - void addAfterKeyguardGoneRunnable(Runnable runnable); - - /** * Close the shade if it was open * * @return true if the shade was open, else false @@ -127,16 +90,4 @@ public interface ShadeController { * @param animate */ void collapsePanel(boolean animate); - - /** - * Callback to tell the shade controller that an activity launch animation was canceled - */ - void onLaunchAnimationCancelled(); - - /** - * Callback to notify the shade controller that a {@link ActivatableNotificationView} has become - * inactive - */ - void onActivationReset(); - } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 5575d10c7fe1..e31ad9fd4262 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1239,6 +1239,7 @@ public class StatusBar extends SystemUI implements DemoMode, mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController, mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController, mNotificationAlertingManager, rowBinder, mKeyguardStateController, + mKeyguardIndicationController, this /* statusBar */, mCommandQueue); mNotificationListController = @@ -1263,7 +1264,7 @@ public class StatusBar extends SystemUI implements DemoMode, mRemoteInputUriController.attach(mEntryManager); rowBinder.setNotificationClicker(new NotificationClicker( - this, mBubbleController, mNotificationActivityStarter)); + Optional.of(this), mBubbleController, mNotificationActivityStarter)); mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager); mNotificationListController.bind(); @@ -1282,17 +1283,13 @@ public class StatusBar extends SystemUI implements DemoMode, mCommandQueue.disable(mDisplayId, state1, state2, false /* animate */); } - @Override - public void addAfterKeyguardGoneRunnable(Runnable runnable) { - mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); - } - - @Override - public boolean isDozing() { - return mDozing; - } - - @Override + /** + * Ask the display to wake up if currently dozing, else do nothing + * + * @param time when to wake up + * @param where the view requesting the wakeup + * @param why the reason for the wake up + */ public void wakeUpIfDozing(long time, View where, String why) { if (mDozing) { mPowerManager.wakeUp( @@ -1708,7 +1705,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { mEntryManager.updateNotifications("onHeadsUpStateChanged"); - if (isDozing() && isHeadsUp) { + if (mStatusBarStateController.isDozing() && isHeadsUp) { entry.setPulseSuppressed(false); mDozeServiceHost.fireNotificationPulse(entry); if (mDozeServiceHost.isPulsing()) { @@ -3453,16 +3450,11 @@ public class StatusBar extends SystemUI implements DemoMode, private void showBouncerIfKeyguard() { if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) && !mKeyguardViewMediator.isHiding()) { - showBouncer(true /* scrimmed */); + mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */); } } @Override - public void showBouncer(boolean scrimmed) { - mStatusBarKeyguardViewManager.showBouncer(scrimmed); - } - - @Override public void instantExpandNotificationsPanel() { // Make our window larger and the panel expanded. makeExpandedVisible(true); @@ -3583,10 +3575,6 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarKeyguardViewManager.isOccluded()); } - public void onActivationReset() { - mKeyguardIndicationController.hideTransientIndication(); - } - public void onTrackingStarted() { runPostCollapseRunnables(); } @@ -3628,7 +3616,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void onTrackingStopped(boolean expand) { if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { if (!expand && !mKeyguardStateController.canDismissLockScreen()) { - showBouncer(false /* scrimmed */); + mStatusBarKeyguardViewManager.showBouncer(false /* scrimmed */); } } } @@ -3688,15 +3676,6 @@ public class StatusBar extends SystemUI implements DemoMode, } /** - * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}. - */ - public void goToKeyguard() { - if (mState == StatusBarState.SHADE_LOCKED) { - mStatusBarStateController.setState(StatusBarState.KEYGUARD); - } - } - - /** * Propagation of the bouncer state, indicating that it's fully visible. */ public void setBouncerShowing(boolean bouncerShowing) { @@ -4019,7 +3998,8 @@ public class StatusBar extends SystemUI implements DemoMode, } public boolean shouldIgnoreTouch() { - return isDozing() && mDozeServiceHost.getIgnoreTouchWhilePulsing(); + return mStatusBarStateController.isDozing() + && mDozeServiceHost.getIgnoreTouchWhilePulsing(); } // Begin Extra BaseStatusBar methods. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 31d03621d23b..dac4e585c1ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -365,6 +365,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb cancelPendingWakeupAction(); } + /** + * Shows the keyguard bouncer - the password challenge on the lock screen + * + * @param scrimmed true when the bouncer should show scrimmed, false when the user will be + * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)} + */ public void showBouncer(boolean scrimmed) { if (mShowing && !mBouncer.isShowing()) { mBouncer.show(false /* resetSecuritySelection */, scrimmed); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index e2832587e2ea..1988b42be14f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -105,6 +105,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final NotificationPresenter mPresenter; private final LockPatternUtils mLockPatternUtils; private final HeadsUpManagerPhone mHeadsUpManager; + private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final KeyguardManager mKeyguardManager; private final ActivityLaunchAnimator mActivityLaunchAnimator; private final IStatusBarService mBarService; @@ -122,7 +123,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit NotificationPresenter presenter, NotificationEntryManager entryManager, HeadsUpManagerPhone headsUpManager, ActivityStarter activityStarter, ActivityLaunchAnimator activityLaunchAnimator, IStatusBarService statusBarService, - StatusBarStateController statusBarStateController, KeyguardManager keyguardManager, + StatusBarStateController statusBarStateController, + StatusBarKeyguardViewManager statusBarKeyguardViewManager, + KeyguardManager keyguardManager, IDreamManager dreamManager, NotificationRemoteInputManager remoteInputManager, StatusBarRemoteInputCallback remoteInputCallback, NotificationGroupManager groupManager, NotificationLockscreenUserManager lockscreenUserManager, @@ -139,6 +142,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mActivityLaunchAnimator = activityLaunchAnimator; mBarService = statusBarService; mCommandQueue = commandQueue; + mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mKeyguardManager = keyguardManager; mDreamManager = dreamManager; mRemoteInputManager = remoteInputManager; @@ -258,7 +262,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mShadeController.collapsePanel(true /* animate */); } else if (mKeyguardStateController.isShowing() && mStatusBar.isOccluded()) { - mShadeController.addAfterKeyguardGoneRunnable(runnable); + mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); mShadeController.collapsePanel(); } else { mBackgroundHandler.postAtFrontOfQueue(runnable); @@ -504,6 +508,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final ActivityStarter mActivityStarter; private final IStatusBarService mStatusBarService; private final StatusBarStateController mStatusBarStateController; + private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final KeyguardManager mKeyguardManager; private final IDreamManager mDreamManager; private final NotificationRemoteInputManager mRemoteInputManager; @@ -533,6 +538,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit ActivityStarter activityStarter, IStatusBarService statusBarService, StatusBarStateController statusBarStateController, + StatusBarKeyguardViewManager statusBarKeyguardViewManager, KeyguardManager keyguardManager, IDreamManager dreamManager, NotificationRemoteInputManager remoteInputManager, @@ -556,6 +562,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mActivityStarter = activityStarter; mStatusBarService = statusBarService; mStatusBarStateController = statusBarStateController; + mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mKeyguardManager = keyguardManager; mDreamManager = dreamManager; mRemoteInputManager = remoteInputManager; @@ -601,6 +608,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mActivityLaunchAnimator, mStatusBarService, mStatusBarStateController, + mStatusBarKeyguardViewManager, mKeyguardManager, mDreamManager, mRemoteInputManager, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 6650cf6a5af6..2649166bfcbf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -49,6 +49,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; @@ -113,6 +114,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, private final DozeScrimController mDozeScrimController; private final ScrimController mScrimController; private final Context mContext; + private final KeyguardIndicationController mKeyguardIndicationController; private final StatusBar mStatusBar; private final CommandQueue mCommandQueue; @@ -141,6 +143,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, NotificationAlertingManager notificationAlertingManager, NotificationRowBinderImpl notificationRowBinder, KeyguardStateController keyguardStateController, + KeyguardIndicationController keyguardIndicationController, StatusBar statusBar, CommandQueue commandQueue) { mContext = context; @@ -148,6 +151,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mNotificationPanel = panel; mHeadsUpManager = headsUp; mDynamicPrivacyController = dynamicPrivacyController; + mKeyguardIndicationController = keyguardIndicationController; // TODO: use KeyguardStateController#isOccluded to remove this dependency mStatusBar = statusBar; mCommandQueue = commandQueue; @@ -323,7 +327,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mCommandQueue.animateCollapsePanels(); } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED && !isCollapsing()) { - mShadeController.goToKeyguard(); + mStatusBarStateController.setState(StatusBarState.KEYGUARD); } } } @@ -420,7 +424,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, public void onActivationReset(ActivatableNotificationView view) { if (view == mNotificationPanel.getActivatedChild()) { mNotificationPanel.setActivatedChild(null); - mShadeController.onActivationReset(); + mKeyguardIndicationController.hideTransientIndication(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java index 3e6ba4dacb71..2012b5703504 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java @@ -64,6 +64,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, private final ActivityStarter mActivityStarter; private final Lazy<ShadeController> mShadeControllerLazy; private final Context mContext; + private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final ActivityIntentHelper mActivityIntentHelper; private final NotificationGroupManager mGroupManager; private View mPendingWorkRemoteInputView; @@ -81,9 +82,11 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, NotificationLockscreenUserManager notificationLockscreenUserManager, KeyguardStateController keyguardStateController, StatusBarStateController statusBarStateController, + StatusBarKeyguardViewManager statusBarKeyguardViewManager, ActivityStarter activityStarter, Lazy<ShadeController> shadeControllerLazy, CommandQueue commandQueue) { mContext = context; + mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mContext.registerReceiverAsUser(mChallengeReceiver, UserHandle.ALL, new IntentFilter(ACTION_DEVICE_LOCKED_CHANGED), null, null); mLockscreenUserManager = notificationLockscreenUserManager; @@ -118,7 +121,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, if (!row.isPinned()) { mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); } - mShadeControllerLazy.get().showBouncer(true /* scrimmed */); + mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */); mPendingRemoteInputView = clicked; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java index 3935df02fd91..f8929e01adb8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java @@ -263,7 +263,7 @@ public class StatusBarWindowViewController { if (isDown) { mStackScrollLayout.closeControlsIfOutsideTouch(ev); } - if (mService.isDozing()) { + if (mStatusBarStateController.isDozing()) { mService.mDozeScrimController.extendPulse(); } // In case we start outside of the view bounds (below the status bar), we need to @@ -284,7 +284,8 @@ public class StatusBarWindowViewController { @Override public boolean shouldInterceptTouchEvent(MotionEvent ev) { - if (mService.isDozing() && !mService.isPulsing() && !mDockManager.isDocked()) { + if (mStatusBarStateController.isDozing() && !mService.isPulsing() + && !mDockManager.isDocked()) { // Capture all touch events in always-on. return true; } @@ -292,7 +293,7 @@ public class StatusBarWindowViewController { if (notificationPanelView.isFullyExpanded() && mDragDownHelper.isDragDownEnabled() && !mService.isBouncerShowing() - && !mService.isDozing()) { + && !mStatusBarStateController.isDozing()) { intercept = mDragDownHelper.onInterceptTouchEvent(ev); } @@ -312,7 +313,7 @@ public class StatusBarWindowViewController { @Override public boolean handleTouchEvent(MotionEvent ev) { boolean handled = false; - if (mService.isDozing()) { + if (mStatusBarStateController.isDozing()) { handled = !mService.isPulsing(); } if ((mDragDownHelper.isDragDownEnabled() && !handled) @@ -358,7 +359,7 @@ public class StatusBarWindowViewController { break; case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_UP: - if (mService.isDozing()) { + if (mStatusBarStateController.isDozing()) { MediaSessionLegacyHelper.getHelper(mView.getContext()) .sendVolumeKeyEvent( event, AudioManager.USE_DEFAULT_STREAM_TYPE, true); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java index 9b685f0ad0f6..74739e19ede9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java @@ -16,32 +16,44 @@ package com.android.systemui.statusbar.tv; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.annotation.IntDef; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.PixelFormat; -import android.graphics.drawable.Drawable; +import android.util.ArraySet; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; -import android.view.ViewPropertyAnimator; import android.view.ViewTreeObserver; import android.view.WindowManager; -import android.widget.ImageView; import android.widget.TextView; import com.android.systemui.R; -import java.util.ArrayList; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Arrays; -import java.util.List; - +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; + +/** + * A component of {@link TvStatusBar} responsible for notifying the user whenever an application is + * recording audio. + * + * @see TvStatusBar + */ class AudioRecordingDisclosureBar { private static final String TAG = "AudioRecordingDisclosureBar"; private static final boolean DEBUG = false; @@ -50,121 +62,310 @@ class AudioRecordingDisclosureBar { // CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest private static final String LAYOUT_PARAMS_TITLE = "MicrophoneCaptureIndicator"; - private static final int ANIM_DURATION_MS = 150; + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"STATE_"}, value = { + STATE_NOT_SHOWN, + STATE_APPEARING, + STATE_SHOWN, + STATE_MINIMIZING, + STATE_MINIMIZED, + STATE_MAXIMIZING, + STATE_DISAPPEARING + }) + public @interface State {} + + private static final int STATE_NOT_SHOWN = 0; + private static final int STATE_APPEARING = 1; + private static final int STATE_SHOWN = 2; + private static final int STATE_MINIMIZING = 3; + private static final int STATE_MINIMIZED = 4; + private static final int STATE_MAXIMIZING = 5; + private static final int STATE_DISAPPEARING = 6; + + private static final int ANIMATION_DURATION = 600; + private static final int MAXIMIZED_DURATION = 3000; + private static final int PULSE_BIT_DURATION = 1000; + private static final float PULSE_SCALE = 1.25f; private final Context mContext; - private final List<String> mAudioRecordingApps = new ArrayList<>(); - private View mView; - private ViewGroup mAppsInfoContainer; + + private View mIndicatorView; + private View mIconTextsContainer; + private View mIconContainerBg; + private View mIcon; + private View mBgRight; + private View mTextsContainers; + private TextView mTextView; + + @State private int mState = STATE_NOT_SHOWN; + private final Set<String> mAudioRecordingApps = new HashSet<>(); + private final Queue<String> mPendingNotifications = new LinkedList<>(); AudioRecordingDisclosureBar(Context context) { mContext = context; } void start() { - // Inflate and add audio recording disclosure bar - createView(); - // Register AppOpsManager callback final AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService( Context.APP_OPS_SERVICE); appOpsManager.startWatchingActive( - new String[]{AppOpsManager.OPSTR_RECORD_AUDIO}, mContext.getMainExecutor(), + new String[]{AppOpsManager.OPSTR_RECORD_AUDIO}, + mContext.getMainExecutor(), new OnActiveRecordingListener()); } - private void createView() { - //TODO(b/142228704): this is to be re-implemented once proper design is completed - mView = View.inflate(mContext, - R.layout.tv_status_bar_audio_recording, null); - mAppsInfoContainer = mView.findViewById(R.id.container); + private void onStartedRecording(String packageName) { + if (!mAudioRecordingApps.add(packageName)) { + // This app is already known to perform recording + return; + } + + switch (mState) { + case STATE_NOT_SHOWN: + show(packageName); + break; + + case STATE_MINIMIZED: + expand(packageName); + break; + + case STATE_DISAPPEARING: + case STATE_APPEARING: + case STATE_MAXIMIZING: + case STATE_SHOWN: + case STATE_MINIMIZING: + // Currently animating or expanded. Thus add to the pending notifications, and it + // will be picked up once the indicator comes to the STATE_MINIMIZED. + mPendingNotifications.add(packageName); + break; + } + } + + private void onDoneRecording(String packageName) { + if (!mAudioRecordingApps.remove(packageName)) { + // Was not marked as an active recorder, do nothing + return; + } + + // If not MINIMIZED, will check whether the indicator should be hidden when the indicator + // comes to the STATE_MINIMIZED eventually. If is in the STATE_MINIMIZED, but there are + // other active recorders - simply ignore. + if (mState == STATE_MINIMIZED && mAudioRecordingApps.isEmpty()) { + hide(); + } + } + + private void show(String packageName) { + // Inflate the indicator view + mIndicatorView = LayoutInflater.from(mContext).inflate( + R.layout.tv_audio_recording_indicator, + null); + mIconTextsContainer = mIndicatorView.findViewById(R.id.icon_texts_container); + mIconContainerBg = mIconTextsContainer.findViewById(R.id.icon_container_bg); + mIcon = mIconTextsContainer.findViewById(R.id.icon_mic); + mTextsContainers = mIconTextsContainer.findViewById(R.id.texts_container); + mTextView = mTextsContainers.findViewById(R.id.text); + mBgRight = mIndicatorView.findViewById(R.id.bg_right); + + // Set up the notification text + final String label = getApplicationLabel(packageName); + mTextView.setText(mContext.getString(R.string.app_accessed_mic, label)); + + // Initially change the visibility to INVISIBLE, wait until and receives the size and + // then animate it moving from "off" the screen correctly + mIndicatorView.setVisibility(View.INVISIBLE); + mIndicatorView + .getViewTreeObserver() + .addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + // Remove the observer + mIndicatorView.getViewTreeObserver().removeOnGlobalLayoutListener( + this); + + // Now that the width of the indicator has been assigned, we can + // move it in from off the screen. + final int initialOffset = mIndicatorView.getWidth(); + final AnimatorSet set = new AnimatorSet(); + set.setDuration(ANIMATION_DURATION); + set.playTogether( + ObjectAnimator.ofFloat(mIndicatorView, + View.TRANSLATION_X, initialOffset, 0), + ObjectAnimator.ofFloat(mIndicatorView, View.ALPHA, 0f, + 1f)); + set.addListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation, + boolean isReverse) { + // Indicator is INVISIBLE at the moment, change it. + mIndicatorView.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationEnd(Animator animation) { + startPulsatingAnimation(); + onExpanded(); + } + }); + set.start(); + } + }); final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams( - MATCH_PARENT, + WRAP_CONTENT, WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); - layoutParams.gravity = Gravity.BOTTOM; + layoutParams.gravity = Gravity.TOP | Gravity.RIGHT; layoutParams.setTitle(LAYOUT_PARAMS_TITLE); layoutParams.packageName = mContext.getPackageName(); - final WindowManager windowManager = (WindowManager) mContext.getSystemService( Context.WINDOW_SERVICE); - windowManager.addView(mView, layoutParams); + windowManager.addView(mIndicatorView, layoutParams); + + mState = STATE_APPEARING; + } - // Set invisible first until it gains its actual size and we are able to hide it by moving - // off the screen - mView.setVisibility(View.INVISIBLE); - mView.getViewTreeObserver().addOnGlobalLayoutListener( - new ViewTreeObserver.OnGlobalLayoutListener() { + private void expand(String packageName) { + final String label = getApplicationLabel(packageName); + mTextView.setText(mContext.getString(R.string.app_accessed_mic, label)); + + final AnimatorSet set = new AnimatorSet(); + set.playTogether( + ObjectAnimator.ofFloat(mIconTextsContainer, View.TRANSLATION_X, 0), + ObjectAnimator.ofFloat(mIconContainerBg, View.ALPHA, 1f), + ObjectAnimator.ofFloat(mTextsContainers, View.ALPHA, 1f), + ObjectAnimator.ofFloat(mBgRight, View.ALPHA, 1f)); + set.setDuration(ANIMATION_DURATION); + set.addListener( + new AnimatorListenerAdapter() { @Override - public void onGlobalLayout() { - // Now that we get the height, we can move the bar off ("below") the screen - final int height = mView.getHeight(); - mView.setTranslationY(height); - // Remove the observer - mView.getViewTreeObserver() - .removeOnGlobalLayoutListener(this); - // Now, that the view has been measured, and the translation was set to - // move it off the screen, we change the visibility to GONE - mView.setVisibility(View.GONE); + public void onAnimationEnd(Animator animation) { + onExpanded(); } }); + set.start(); + + mState = STATE_MAXIMIZING; } - private void showAudioRecordingDisclosureBar() { - mView.setVisibility(View.VISIBLE); - mView.animate() - .translationY(0f) - .setDuration(ANIM_DURATION_MS) - .start(); + private void minimize() { + final int targetOffset = mTextsContainers.getWidth(); + final AnimatorSet set = new AnimatorSet(); + set.playTogether( + ObjectAnimator.ofFloat(mIconTextsContainer, View.TRANSLATION_X, targetOffset), + ObjectAnimator.ofFloat(mIconContainerBg, View.ALPHA, 0f), + ObjectAnimator.ofFloat(mTextsContainers, View.ALPHA, 0f), + ObjectAnimator.ofFloat(mBgRight, View.ALPHA, 0f)); + set.setDuration(ANIMATION_DURATION); + set.addListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + onMinimized(); + } + }); + set.start(); + + mState = STATE_MINIMIZING; } - private void addToAudioRecordingDisclosureBar(String packageName) { - final PackageManager pm = mContext.getPackageManager(); - final ApplicationInfo appInfo; - try { - appInfo = pm.getApplicationInfo(packageName, 0); - } catch (PackageManager.NameNotFoundException e) { - return; + private void hide() { + final int targetOffset = + mIndicatorView.getWidth() - (int) mIconTextsContainer.getTranslationX(); + final AnimatorSet set = new AnimatorSet(); + set.playTogether( + ObjectAnimator.ofFloat(mIndicatorView, View.TRANSLATION_X, targetOffset), + ObjectAnimator.ofFloat(mIcon, View.ALPHA, 0f)); + set.setDuration(ANIMATION_DURATION); + set.addListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + onHidden(); + } + }); + set.start(); + + mState = STATE_DISAPPEARING; + } + + private void onExpanded() { + mState = STATE_SHOWN; + + mIndicatorView.postDelayed(this::minimize, MAXIMIZED_DURATION); + } + + private void onMinimized() { + mState = STATE_MINIMIZED; + + if (!mPendingNotifications.isEmpty()) { + // There is a new application that started recording, tell the user about it. + expand(mPendingNotifications.poll()); + } else if (mAudioRecordingApps.isEmpty()) { + // Nobody is recording anymore, remove the indicator. + hide(); } - final CharSequence label = pm.getApplicationLabel(appInfo); - final Drawable icon = pm.getApplicationIcon(appInfo); + } + + private void onHidden() { + final WindowManager windowManager = (WindowManager) mContext.getSystemService( + Context.WINDOW_SERVICE); + windowManager.removeView(mIndicatorView); - final View view = LayoutInflater.from(mContext).inflate(R.layout.tv_item_app_info, - mAppsInfoContainer, false); - ((TextView) view.findViewById(R.id.title)).setText(label); - ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(icon); + mIndicatorView = null; + mIconTextsContainer = null; + mIconContainerBg = null; + mIcon = null; + mTextsContainers = null; + mTextView = null; + mBgRight = null; - mAppsInfoContainer.addView(view); + mState = STATE_NOT_SHOWN; } - private void removeFromAudioRecordingDisclosureBar(int index) { - mAppsInfoContainer.removeViewAt(index); + private void startPulsatingAnimation() { + final View pulsatingView = mIconTextsContainer.findViewById(R.id.pulsating_circle); + final ObjectAnimator animator = + ObjectAnimator.ofPropertyValuesHolder( + pulsatingView, + PropertyValuesHolder.ofFloat(View.SCALE_X, PULSE_SCALE), + PropertyValuesHolder.ofFloat(View.SCALE_Y, PULSE_SCALE)); + animator.setDuration(PULSE_BIT_DURATION); + animator.setRepeatCount(ObjectAnimator.INFINITE); + animator.setRepeatMode(ObjectAnimator.REVERSE); + animator.start(); } - private void hideAudioRecordingDisclosureBar() { - final ViewPropertyAnimator animator = mView.animate(); - animator.translationY(mView.getHeight()) - .setDuration(ANIM_DURATION_MS) - .withEndAction(() -> mView.setVisibility(View.GONE)) - .start(); + private String getApplicationLabel(String packageName) { + final PackageManager pm = mContext.getPackageManager(); + final ApplicationInfo appInfo; + try { + appInfo = pm.getApplicationInfo(packageName, 0); + } catch (PackageManager.NameNotFoundException e) { + return packageName; + } + return pm.getApplicationLabel(appInfo).toString(); } private class OnActiveRecordingListener implements AppOpsManager.OnOpActiveChangedListener { - private final List<String> mExemptApps; + private final Set<String> mExemptApps; private OnActiveRecordingListener() { - mExemptApps = Arrays.asList(mContext.getResources().getStringArray( - R.array.audio_recording_disclosure_exempt_apps)); + mExemptApps = new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray( + R.array.audio_recording_disclosure_exempt_apps))); } @Override public void onOpActiveChanged(String op, int uid, String packageName, boolean active) { if (DEBUG) { Log.d(TAG, - "OP_RECORD_AUDIO active change, active=" + active + ", app=" + packageName); + "OP_RECORD_AUDIO active change, active=" + active + ", app=" + + packageName); } if (mExemptApps.contains(packageName)) { @@ -174,37 +375,10 @@ class AudioRecordingDisclosureBar { return; } - final boolean alreadyTracking = mAudioRecordingApps.contains(packageName); - if ((active && alreadyTracking) || (!active && !alreadyTracking)) { - if (DEBUG) { - Log.d(TAG, "\t- nothing changed"); - } - return; - } - if (active) { - if (DEBUG) { - Log.d(TAG, "\t- new recording app"); - } - - if (mAudioRecordingApps.isEmpty()) { - showAudioRecordingDisclosureBar(); - } - - mAudioRecordingApps.add(packageName); - addToAudioRecordingDisclosureBar(packageName); + onStartedRecording(packageName); } else { - if (DEBUG) { - Log.d(TAG, "\t- not recording any more"); - } - - final int index = mAudioRecordingApps.indexOf(packageName); - removeFromAudioRecordingDisclosureBar(index); - mAudioRecordingApps.remove(index); - - if (mAudioRecordingApps.isEmpty()) { - hideAudioRecordingDisclosureBar(); - } + onDoneRecording(packageName); } } } diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java index 2d6c4a62047d..ac15e2dd6df9 100644 --- a/packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java +++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java @@ -62,11 +62,4 @@ public interface DelayableExecutor extends Executor { * @return A Runnable that, when run, removes the supplied argument from the Executor queue. */ Runnable executeAtTime(Runnable r, long uptimeMillis, TimeUnit unit); - - /** - * Remove all pending Runnables. - * - */ - void removeAll(); - } diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java index 2a99de3ac5ad..7e7732135e3a 100644 --- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java @@ -50,9 +50,4 @@ public class ExecutorImpl extends HandlerExecutor implements DelayableExecutor { return () -> mHandler.removeCallbacksAndMessages(token); } - - @Override - public void removeAll() { - mHandler.removeCallbacksAndMessages(null); - } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java index 5ed8b8f9e362..e1210011c7a4 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/Events.java +++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java @@ -21,7 +21,11 @@ import android.media.AudioSystem; import android.provider.Settings.Global; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; +import com.android.internal.logging.UiEventLoggerImpl; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.plugins.VolumeDialogController.State; @@ -37,7 +41,7 @@ public class Events { public static final int EVENT_DISMISS_DIALOG = 1; // (reason|int) public static final int EVENT_ACTIVE_STREAM_CHANGED = 2; // (stream|int) public static final int EVENT_EXPAND = 3; // (expand|bool) - public static final int EVENT_KEY = 4; + public static final int EVENT_KEY = 4; // (stream|int) (lastAudibleStreamVolume) public static final int EVENT_COLLECTION_STARTED = 5; public static final int EVENT_COLLECTION_STOPPED = 6; public static final int EVENT_ICON_CLICK = 7; // (stream|int) (icon_state|int) @@ -49,7 +53,7 @@ public class Events { public static final int EVENT_ZEN_MODE_CHANGED = 13; // (mode|int) public static final int EVENT_SUPPRESSOR_CHANGED = 14; // (component|string) (name|string) public static final int EVENT_MUTE_CHANGED = 15; // (stream|int) (muted|bool) - public static final int EVENT_TOUCH_LEVEL_DONE = 16; // (stream|int) (level|bool) + public static final int EVENT_TOUCH_LEVEL_DONE = 16; // (stream|int) (level|int) public static final int EVENT_ZEN_CONFIG_CHANGED = 17; // (allow/disallow|string) public static final int EVENT_RINGER_TOGGLE = 18; // (ringer_mode) public static final int EVENT_SHOW_USB_OVERHEAT_ALARM = 19; // (reason|int) (keyguard|bool) @@ -122,103 +126,363 @@ public class Events { public static final int ICON_STATE_MUTE = 2; public static final int ICON_STATE_VIBRATE = 3; + @VisibleForTesting + public enum VolumeDialogOpenEvent implements UiEventLogger.UiEventEnum { + //TODO zap the lock/unlock distinction + INVALID(0), + @UiEvent(doc = "The volume dialog was shown because the volume changed") + VOLUME_DIALOG_SHOW_VOLUME_CHANGED(128), + @UiEvent(doc = "The volume dialog was shown because the volume changed remotely") + VOLUME_DIALOG_SHOW_REMOTE_VOLUME_CHANGED(129), + @UiEvent(doc = "The volume dialog was shown because the usb high temperature alarm changed") + VOLUME_DIALOG_SHOW_USB_TEMP_ALARM_CHANGED(130); + + private final int mId; + VolumeDialogOpenEvent(int id) { + mId = id; + } + public int getId() { + return mId; + } + static VolumeDialogOpenEvent fromReasons(int reason) { + switch (reason) { + case SHOW_REASON_VOLUME_CHANGED: + return VOLUME_DIALOG_SHOW_VOLUME_CHANGED; + case SHOW_REASON_REMOTE_VOLUME_CHANGED: + return VOLUME_DIALOG_SHOW_REMOTE_VOLUME_CHANGED; + case SHOW_REASON_USB_OVERHEAD_ALARM_CHANGED: + return VOLUME_DIALOG_SHOW_USB_TEMP_ALARM_CHANGED; + } + return INVALID; + } + } + + @VisibleForTesting + public enum VolumeDialogCloseEvent implements UiEventLogger.UiEventEnum { + INVALID(0), + @UiEvent(doc = "The volume dialog was dismissed because of a touch outside the dialog") + VOLUME_DIALOG_DISMISS_TOUCH_OUTSIDE(134), + @UiEvent(doc = "The system asked the volume dialog to close, e.g. for a navigation bar " + + "touch, or ActivityManager ACTION_CLOSE_SYSTEM_DIALOGS broadcast.") + VOLUME_DIALOG_DISMISS_SYSTEM(135), + @UiEvent(doc = "The volume dialog was dismissed because it timed out") + VOLUME_DIALOG_DISMISS_TIMEOUT(136), + @UiEvent(doc = "The volume dialog was dismissed because the screen turned off") + VOLUME_DIALOG_DISMISS_SCREEN_OFF(137), + @UiEvent(doc = "The volume dialog was dismissed because the settings icon was clicked") + VOLUME_DIALOG_DISMISS_SETTINGS(138), + // reserving 139 for DISMISS_REASON_DONE_CLICKED which is currently unused + @UiEvent(doc = "The volume dialog was dismissed because the stream no longer exists") + VOLUME_DIALOG_DISMISS_STREAM_GONE(140), + // reserving 141 for DISMISS_REASON_OUTPUT_CHOOSER which is currently unused + @UiEvent(doc = "The volume dialog was dismissed because the usb high temperature alarm " + + "changed") + VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED(142); + + private final int mId; + VolumeDialogCloseEvent(int id) { + mId = id; + } + public int getId() { + return mId; + } + + static VolumeDialogCloseEvent fromReason(int reason) { + switch (reason) { + case DISMISS_REASON_TOUCH_OUTSIDE: + return VOLUME_DIALOG_DISMISS_TOUCH_OUTSIDE; + case DISMISS_REASON_VOLUME_CONTROLLER: + return VOLUME_DIALOG_DISMISS_SYSTEM; + case DISMISS_REASON_TIMEOUT: + return VOLUME_DIALOG_DISMISS_TIMEOUT; + case DISMISS_REASON_SCREEN_OFF: + return VOLUME_DIALOG_DISMISS_SCREEN_OFF; + case DISMISS_REASON_SETTINGS_CLICKED: + return VOLUME_DIALOG_DISMISS_SETTINGS; + case DISMISS_STREAM_GONE: + return VOLUME_DIALOG_DISMISS_STREAM_GONE; + case DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED: + return VOLUME_DIALOG_DISMISS_USB_TEMP_ALARM_CHANGED; + } + return INVALID; + } + } + + @VisibleForTesting + public enum VolumeDialogEvent implements UiEventLogger.UiEventEnum { + INVALID(0), + @UiEvent(doc = "The volume dialog settings icon was clicked") + VOLUME_DIALOG_SETTINGS_CLICK(143), + @UiEvent(doc = "The volume dialog details were expanded") + VOLUME_DIALOG_EXPAND_DETAILS(144), + @UiEvent(doc = "The volume dialog details were collapsed") + VOLUME_DIALOG_COLLAPSE_DETAILS(145), + @UiEvent(doc = "The active audio stream changed") + VOLUME_DIALOG_ACTIVE_STREAM_CHANGED(146), + @UiEvent(doc = "The audio stream was muted via icon") + VOLUME_DIALOG_MUTE_STREAM(147), + @UiEvent(doc = "The audio stream was unmuted via icon") + VOLUME_DIALOG_UNMUTE_STREAM(148), + @UiEvent(doc = "The audio stream was set to vibrate via icon") + VOLUME_DIALOG_TO_VIBRATE_STREAM(149), + @UiEvent(doc = "The audio stream was set to non-silent via slider") + VOLUME_DIALOG_SLIDER(150), + @UiEvent(doc = "The audio stream was set to silent via slider") + VOLUME_DIALOG_SLIDER_TO_ZERO(151), + @UiEvent(doc = "The audio volume was adjusted to silent via key") + VOLUME_KEY_TO_ZERO(152), + @UiEvent(doc = "The audio volume was adjusted to non-silent via key") + VOLUME_KEY(153), + @UiEvent(doc = "The ringer mode was toggled to silent") + RINGER_MODE_SILENT(154), + @UiEvent(doc = "The ringer mode was toggled to vibrate") + RINGER_MODE_VIBRATE(155), + @UiEvent(doc = "The ringer mode was toggled to normal") + RINGER_MODE_NORMAL(156), + @UiEvent(doc = "USB Overheat alarm was raised") + USB_OVERHEAT_ALARM(160), + @UiEvent(doc = "USB Overheat alarm was dismissed") + USB_OVERHEAT_ALARM_DISMISSED(161); + + private final int mId; + + VolumeDialogEvent(int id) { + mId = id; + } + + public int getId() { + return mId; + } + + static VolumeDialogEvent fromIconState(int iconState) { + switch (iconState) { + case ICON_STATE_UNMUTE: + return VOLUME_DIALOG_UNMUTE_STREAM; + case ICON_STATE_MUTE: + return VOLUME_DIALOG_MUTE_STREAM; + case ICON_STATE_VIBRATE: + return VOLUME_DIALOG_TO_VIBRATE_STREAM; + default: + return INVALID; + } + } + + static VolumeDialogEvent fromSliderLevel(int level) { + return level == 0 ? VOLUME_DIALOG_SLIDER_TO_ZERO : VOLUME_DIALOG_SLIDER; + } + + static VolumeDialogEvent fromKeyLevel(int level) { + return level == 0 ? VOLUME_KEY_TO_ZERO : VOLUME_KEY; + } + + static VolumeDialogEvent fromRingerMode(int ringerMode) { + switch (ringerMode) { + case AudioManager.RINGER_MODE_SILENT: + return RINGER_MODE_SILENT; + case AudioManager.RINGER_MODE_VIBRATE: + return RINGER_MODE_VIBRATE; + case AudioManager.RINGER_MODE_NORMAL: + return RINGER_MODE_NORMAL; + default: + return INVALID; + } + } + } + + @VisibleForTesting + public enum ZenModeEvent implements UiEventLogger.UiEventEnum { + INVALID(0), + @UiEvent(doc = "Zen (do not disturb) mode was toggled to off") + ZEN_MODE_OFF(156), + @UiEvent(doc = "Zen (do not disturb) mode was toggled to important interruptions only") + ZEN_MODE_IMPORTANT_ONLY(157), + @UiEvent(doc = "Zen (do not disturb) mode was toggled to alarms only") + ZEN_MODE_ALARMS_ONLY(158), + @UiEvent(doc = "Zen (do not disturb) mode was toggled to block all interruptions") + ZEN_MODE_NO_INTERRUPTIONS(159); + + private final int mId; + ZenModeEvent(int id) { + mId = id; + } + public int getId() { + return mId; + } + + static ZenModeEvent fromZenMode(int zenMode) { + switch (zenMode) { + case Global.ZEN_MODE_OFF: return ZEN_MODE_OFF; + case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return ZEN_MODE_IMPORTANT_ONLY; + case Global.ZEN_MODE_ALARMS: return ZEN_MODE_ALARMS_ONLY; + case Global.ZEN_MODE_NO_INTERRUPTIONS: return ZEN_MODE_NO_INTERRUPTIONS; + default: return INVALID; + } + } + } + public static Callback sCallback; + @VisibleForTesting + static MetricsLogger sLegacyLogger = new MetricsLogger(); + @VisibleForTesting + static UiEventLogger sUiEventLogger = new UiEventLoggerImpl(); /** - * Logs an event to the system log and the event log. + * Logs an event to the system log, to sCallback if present, and to the logEvent destinations. * @param tag One of the EVENT_* codes above. * @param list Any additional event-specific arguments, documented above. */ public static void writeEvent(int tag, Object... list) { - MetricsLogger logger = new MetricsLogger(); final long time = System.currentTimeMillis(); + Log.i(TAG, logEvent(tag, list)); + if (sCallback != null) { + sCallback.writeEvent(time, tag, list); + } + } + + /** + * Logs an event to the event log and UiEvent (Westworld) logging. Compare writeEvent, which + * adds more log destinations. + * @param tag One of the EVENT_* codes above. + * @param list Any additional event-specific arguments, documented above. + * @return String a readable description of the event. Begins "writeEvent <tag_description>" + * if the tag is valid. + */ + public static String logEvent(int tag, Object... list) { + if (tag >= EVENT_TAGS.length) { + return ""; + } final StringBuilder sb = new StringBuilder("writeEvent ").append(EVENT_TAGS[tag]); - if (list != null && list.length > 0) { - sb.append(" "); - switch (tag) { - case EVENT_SHOW_DIALOG: - logger.visible(MetricsEvent.VOLUME_DIALOG); - logger.histogram("volume_from_keyguard", - (Boolean) list[1] ? 1 : 0); - sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]); - break; - case EVENT_EXPAND: - logger.visibility(MetricsEvent.VOLUME_DIALOG_DETAILS, - (Boolean) list[0]); - sb.append(list[0]); - break; - case EVENT_DISMISS_DIALOG: - logger.hidden(MetricsEvent.VOLUME_DIALOG); - sb.append(DISMISS_REASONS[(Integer) list[0]]); - break; - case EVENT_ACTIVE_STREAM_CHANGED: - logger.action(MetricsEvent.ACTION_VOLUME_STREAM, - (Integer) list[0]); - sb.append(AudioSystem.streamToString((Integer) list[0])); - break; - case EVENT_ICON_CLICK: - logger.action(MetricsEvent.ACTION_VOLUME_ICON, - (Integer) list[0]); - sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ') - .append(iconStateToString((Integer) list[1])); - break; - case EVENT_TOUCH_LEVEL_DONE: - logger.action(MetricsEvent.ACTION_VOLUME_SLIDER, - (Integer) list[1]); - // fall through - case EVENT_TOUCH_LEVEL_CHANGED: - case EVENT_LEVEL_CHANGED: - case EVENT_MUTE_CHANGED: - sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ') - .append(list[1]); - break; - case EVENT_KEY: - logger.action(MetricsEvent.ACTION_VOLUME_KEY, - (Integer) list[0]); + // Handle events without extra data + if (list == null || list.length == 0) { + if (tag == EVENT_SETTINGS_CLICK) { + sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_SETTINGS); + sUiEventLogger.log(VolumeDialogEvent.VOLUME_DIALOG_SETTINGS_CLICK); + } + return sb.toString(); + } + // Handle events with extra data. We've established list[0] exists. + sb.append(" "); + switch (tag) { + case EVENT_SHOW_DIALOG: + sLegacyLogger.visible(MetricsEvent.VOLUME_DIALOG); + if (list.length > 1) { + final Integer reason = (Integer) list[0]; + final Boolean keyguard = (Boolean) list[1]; + sLegacyLogger.histogram("volume_from_keyguard", keyguard ? 1 : 0); + sUiEventLogger.log(VolumeDialogOpenEvent.fromReasons(reason)); + sb.append(SHOW_REASONS[reason]).append(" keyguard=").append(keyguard); + } + break; + case EVENT_EXPAND: { + final Boolean expand = (Boolean) list[0]; + sLegacyLogger.visibility(MetricsEvent.VOLUME_DIALOG_DETAILS, expand); + sUiEventLogger.log(expand ? VolumeDialogEvent.VOLUME_DIALOG_EXPAND_DETAILS + : VolumeDialogEvent.VOLUME_DIALOG_COLLAPSE_DETAILS); + sb.append(expand); + break; + } + case EVENT_DISMISS_DIALOG: { + sLegacyLogger.hidden(MetricsEvent.VOLUME_DIALOG); + final Integer reason = (Integer) list[0]; + sUiEventLogger.log(VolumeDialogCloseEvent.fromReason(reason)); + sb.append(DISMISS_REASONS[reason]); + break; + } + case EVENT_ACTIVE_STREAM_CHANGED: { + final Integer stream = (Integer) list[0]; + sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_STREAM, stream); + sUiEventLogger.log(VolumeDialogEvent.VOLUME_DIALOG_ACTIVE_STREAM_CHANGED); + sb.append(AudioSystem.streamToString(stream)); + break; + } + case EVENT_ICON_CLICK: + if (list.length > 1) { + final Integer stream = (Integer) list[0]; + sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_ICON, stream); + final Integer iconState = (Integer) list[1]; + sUiEventLogger.log(VolumeDialogEvent.fromIconState(iconState)); + sb.append(AudioSystem.streamToString(stream)).append(' ') + .append(iconStateToString(iconState)); + } + break; + case EVENT_TOUCH_LEVEL_DONE: // (stream|int) (level|int) + if (list.length > 1) { + final Integer level = (Integer) list[1]; + sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_SLIDER, level); + sUiEventLogger.log(VolumeDialogEvent.fromSliderLevel(level)); + } + // fall through + case EVENT_TOUCH_LEVEL_CHANGED: + case EVENT_LEVEL_CHANGED: + case EVENT_MUTE_CHANGED: // (stream|int) (level|int) + if (list.length > 1) { sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ') .append(list[1]); - break; - case EVENT_RINGER_TOGGLE: - logger.action(MetricsEvent.ACTION_VOLUME_RINGER_TOGGLE, (Integer) list[0]); - break; - case EVENT_SETTINGS_CLICK: - logger.action(MetricsEvent.ACTION_VOLUME_SETTINGS); - break; - case EVENT_EXTERNAL_RINGER_MODE_CHANGED: - logger.action(MetricsEvent.ACTION_RINGER_MODE, - (Integer) list[0]); - // fall through - case EVENT_INTERNAL_RINGER_MODE_CHANGED: - sb.append(ringerModeToString((Integer) list[0])); - break; - case EVENT_ZEN_MODE_CHANGED: - sb.append(zenModeToString((Integer) list[0])); - break; - case EVENT_SUPPRESSOR_CHANGED: - sb.append(list[0]).append(' ').append(list[1]); - break; - case EVENT_SHOW_USB_OVERHEAT_ALARM: - logger.visible(MetricsEvent.POWER_OVERHEAT_ALARM); - logger.histogram("show_usb_overheat_alarm", - (Boolean) list[1] ? 1 : 0); - sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]); - break; - case EVENT_DISMISS_USB_OVERHEAT_ALARM: - logger.hidden(MetricsEvent.POWER_OVERHEAT_ALARM); - logger.histogram("dismiss_usb_overheat_alarm", - (Boolean) list[1] ? 1 : 0); - sb.append(DISMISS_REASONS[(Integer) list[0]]) - .append(" keyguard=").append(list[1]); - break; - default: - sb.append(Arrays.asList(list)); - break; + } + break; + case EVENT_KEY: // (stream|int) (lastAudibleStreamVolume) + if (list.length > 1) { + final Integer stream = (Integer) list[0]; + sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_KEY, stream); + final Integer level = (Integer) list[1]; + sUiEventLogger.log(VolumeDialogEvent.fromKeyLevel(level)); + sb.append(AudioSystem.streamToString(stream)).append(' ').append(level); + } + break; + case EVENT_RINGER_TOGGLE: { + final Integer ringerMode = (Integer) list[0]; + sLegacyLogger.action(MetricsEvent.ACTION_VOLUME_RINGER_TOGGLE, ringerMode); + sUiEventLogger.log(VolumeDialogEvent.fromRingerMode(ringerMode)); + sb.append(ringerModeToString(ringerMode)); + break; } + case EVENT_EXTERNAL_RINGER_MODE_CHANGED: { + final Integer ringerMode = (Integer) list[0]; + sLegacyLogger.action(MetricsEvent.ACTION_RINGER_MODE, ringerMode); + } + // fall through + case EVENT_INTERNAL_RINGER_MODE_CHANGED: { + final Integer ringerMode = (Integer) list[0]; + sb.append(ringerModeToString(ringerMode)); + break; + } + case EVENT_ZEN_MODE_CHANGED: { + final Integer zenMode = (Integer) list[0]; + sb.append(zenModeToString(zenMode)); + sUiEventLogger.log(ZenModeEvent.fromZenMode(zenMode)); + break; + } + case EVENT_SUPPRESSOR_CHANGED: // (component|string) (name|string) + if (list.length > 1) { + sb.append(list[0]).append(' ').append(list[1]); + } + break; + case EVENT_SHOW_USB_OVERHEAT_ALARM: + sLegacyLogger.visible(MetricsEvent.POWER_OVERHEAT_ALARM); + sUiEventLogger.log(VolumeDialogEvent.USB_OVERHEAT_ALARM); + if (list.length > 1) { + final Boolean keyguard = (Boolean) list[1]; + sLegacyLogger.histogram("show_usb_overheat_alarm", keyguard ? 1 : 0); + final Integer reason = (Integer) list[0]; + sb.append(SHOW_REASONS[reason]).append(" keyguard=").append(keyguard); + } + break; + case EVENT_DISMISS_USB_OVERHEAT_ALARM: + sLegacyLogger.hidden(MetricsEvent.POWER_OVERHEAT_ALARM); + sUiEventLogger.log(VolumeDialogEvent.USB_OVERHEAT_ALARM_DISMISSED); + if (list.length > 1) { + final Boolean keyguard = (Boolean) list[1]; + sLegacyLogger.histogram("dismiss_usb_overheat_alarm", keyguard ? 1 : 0); + final Integer reason = (Integer) list[0]; + sb.append(DISMISS_REASONS[reason]) + .append(" keyguard=").append(keyguard); + } + break; + default: + sb.append(Arrays.asList(list)); + break; } - Log.i(TAG, sb.toString()); - if (sCallback != null) { - sCallback.writeEvent(time, tag, list); - } + return sb.toString(); } public static void writeState(long time, State state) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt index 2242c1adb1d4..42fbf59fef44 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt @@ -93,7 +93,7 @@ class BroadcastDispatcherTest : SysuiTestCase() { // These should be valid filters `when`(intentFilter.countActions()).thenReturn(1) `when`(intentFilterOther.countActions()).thenReturn(1) - `when`(mockContext.user).thenReturn(user0) + setUserMock(mockContext, user0) } @Test @@ -140,6 +140,18 @@ class BroadcastDispatcherTest : SysuiTestCase() { verify(mockUBRUser1, never()).unregisterReceiver(broadcastReceiver) } + @Test + fun testRegisterCurrentAsActualUser() { + setUserMock(mockContext, user1) + broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, + UserHandle.CURRENT) + + testableLooper.processAllMessages() + + verify(mockUBRUser1).registerReceiver(capture(argumentCaptor)) + assertSame(broadcastReceiver, argumentCaptor.value.receiver) + } + @Test(expected = IllegalArgumentException::class) fun testFilterMustContainActions() { val testFilter = IntentFilter() @@ -186,6 +198,11 @@ class BroadcastDispatcherTest : SysuiTestCase() { broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter) } + private fun setUserMock(mockContext: Context, user: UserHandle) { + `when`(mockContext.user).thenReturn(user) + `when`(mockContext.userId).thenReturn(user.identifier) + } + private class TestBroadcastDispatcher( context: Context, mainHandler: Handler, diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 4c707f45efc1..e0d31d053f76 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -82,6 +82,7 @@ import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.InjectionInflationController; @@ -153,6 +154,8 @@ public class BubbleControllerTest extends SysuiTestCase { private Resources mResources; @Mock private Lazy<ShadeController> mShadeController; + @Mock + private RemoteInputUriController mRemoteInputUriController; private SuperStatusBarViewFactory mSuperStatusBarViewFactory; private BubbleData mBubbleData; @@ -212,7 +215,8 @@ public class BubbleControllerTest extends SysuiTestCase { mZenModeController, mLockscreenUserManager, mNotificationGroupManager, - mNotificationEntryManager); + mNotificationEntryManager, + mRemoteInputUriController); mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener); mBubbleController.setExpandListener(mBubbleExpandListener); @@ -475,7 +479,7 @@ public class BubbleControllerTest extends SysuiTestCase { } @Test - public void testAutoExpand_FailsNotForeground() { + public void testAutoExpand_fails_noFlag() { assertFalse(mBubbleController.isStackExpanded()); setMetadataFlags(mRow.getEntry(), Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */); @@ -494,7 +498,7 @@ public class BubbleControllerTest extends SysuiTestCase { } @Test - public void testAutoExpand_SucceedsForeground() { + public void testAutoExpand_succeeds_withFlag() { setMetadataFlags(mRow.getEntry(), Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, true /* enableFlag */); @@ -512,38 +516,52 @@ public class BubbleControllerTest extends SysuiTestCase { } @Test - public void testSuppressNotif_FailsNotForeground() { + public void testSuppressNotif_onInitialNotif() { setMetadataFlags(mRow.getEntry(), - Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, false /* enableFlag */); + Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */); // Add the suppress notif bubble mEntryListener.onPendingEntryAdded(mRow.getEntry()); mBubbleController.updateBubble(mRow.getEntry()); - // Should not be suppressed because we weren't forground - assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( + // Notif should be suppressed because we were foreground + assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( mRow.getEntry().getKey())); + // Dot + flyout is hidden because notif is suppressed + assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot()); + assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout()); + // # of bubbles should change verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */); } @Test - public void testSuppressNotif_SucceedsForeground() { + public void testSuppressNotif_onUpdateNotif() { + mBubbleController.updateBubble(mRow.getEntry()); + + // Should not be suppressed + assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade( + mRow.getEntry().getKey())); + // Should show dot + assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot()); + + // Update to suppress notif setMetadataFlags(mRow.getEntry(), Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */); - - // Add the suppress notif bubble - mEntryListener.onPendingEntryAdded(mRow.getEntry()); mBubbleController.updateBubble(mRow.getEntry()); - // Notif should be suppressed because we were foreground + // Notif should be suppressed assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade( mRow.getEntry().getKey())); + // Dot + flyout is hidden because notif is suppressed + assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot()); + assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout()); // # of bubbles should change verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */); } + @Test public void testExpandStackAndSelectBubble_removedFirst() { final String key = mRow.getEntry().getKey(); @@ -708,11 +726,13 @@ public class BubbleControllerTest extends SysuiTestCase { ZenModeController zenModeController, NotificationLockscreenUserManager lockscreenUserManager, NotificationGroupManager groupManager, - NotificationEntryManager entryManager) { + NotificationEntryManager entryManager, + RemoteInputUriController remoteInputUriController) { super(context, statusBarWindowController, statusBarStateController, shadeController, data, Runnable::run, configurationController, interruptionStateProvider, - zenModeController, lockscreenUserManager, groupManager, entryManager); + zenModeController, lockscreenUserManager, groupManager, entryManager, + remoteInputUriController); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java index 95c7af31865b..1554abcec3b2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java @@ -42,6 +42,7 @@ import com.android.systemui.bubbles.BubbleData.TimeSource; import com.android.systemui.statusbar.NotificationEntryBuilder; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.google.common.collect.ImmutableList; @@ -119,7 +120,9 @@ public class BubbleDataTest extends SysuiTestCase { .setVisuallyInterruptive(true) .build(); + ExpandableNotificationRow row = mNotificationTestHelper.createBubble(); mEntryDismissed = createBubbleEntry(1, "dismissed", "package.d"); + mEntryDismissed.setRow(row); mBubbleA1 = new Bubble(mContext, mEntryA1); mBubbleA2 = new Bubble(mContext, mEntryA2); @@ -192,9 +195,8 @@ public class BubbleDataTest extends SysuiTestCase { mBubbleData.setListener(mListener); // Test - mBubbleData.notificationEntryUpdated(mEntryInterruptive, /* suppressFlyout */ - false, /* showInShade */ - true); + mBubbleData.notificationEntryUpdated(mEntryInterruptive, + false /* suppressFlyout */, true /* showInShade */); // Verify verifyUpdateReceived(); @@ -208,12 +210,12 @@ public class BubbleDataTest extends SysuiTestCase { mBubbleData.setListener(mListener); // Test - mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ false, /* showInShade */ - true); + mBubbleData.notificationEntryUpdated(mEntryC1, false /* suppressFlyout */, + true /* showInShade */); verifyUpdateReceived(); - mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ false, /* showInShade */ - true); + mBubbleData.notificationEntryUpdated(mEntryC1, false /* suppressFlyout */, + true /* showInShade */); verifyUpdateReceived(); // Verify @@ -225,16 +227,18 @@ public class BubbleDataTest extends SysuiTestCase { public void sameUpdate_NotInShade_showFlyout() { // Setup mBubbleData.setListener(mListener); - setMetadataFlags(mEntryDismissed, - Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, /* enableFlag */ true); // Test - mBubbleData.notificationEntryUpdated(mEntryDismissed, /* suppressFlyout */ false, - /* showInShade */ false); + mBubbleData.notificationEntryUpdated(mEntryDismissed, false /* suppressFlyout */, + false /* showInShade */); verifyUpdateReceived(); - mBubbleData.notificationEntryUpdated(mEntryDismissed, /* suppressFlyout */ - false, /* showInShade */ false); + // Make it look like user swiped away row + mEntryDismissed.getRow().dismiss(false /* refocusOnDismiss */); + assertThat(mBubbleData.getBubbleWithKey(mEntryDismissed.getKey()).showInShade()).isFalse(); + + mBubbleData.notificationEntryUpdated(mEntryDismissed, false /* suppressFlyout */, + false /* showInShade */); verifyUpdateReceived(); // Verify @@ -936,23 +940,6 @@ public class BubbleDataTest extends SysuiTestCase { } /** - * Sets the bubble metadata flags for this entry. These flags are normally set by - * NotificationManagerService when the notification is sent, however, these tests do not - * go through that path so we set them explicitly when testing. - */ - private void setMetadataFlags(NotificationEntry entry, int flag, boolean enableFlag) { - Notification.BubbleMetadata bubbleMetadata = - entry.getSbn().getNotification().getBubbleMetadata(); - int flags = bubbleMetadata.getFlags(); - if (enableFlag) { - flags |= flag; - } else { - flags &= ~flag; - } - bubbleMetadata.setFlags(flags); - } - - /** * No ExpandableNotificationRow is required to test BubbleData. This setup is all that is * required for BubbleData functionality and verification. NotificationTestHelper is used only * as a convenience to create a Notification w/BubbleMetadata. diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageRevealHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageRevealHelperTest.java new file mode 100644 index 000000000000..c827ac7ab963 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageRevealHelperTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.glwallpaper; + +import static com.google.common.truth.Truth.assertThat; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class ImageRevealHelperTest extends SysuiTestCase { + + static final int ANIMATION_DURATION = 500; + ImageRevealHelper mImageRevealHelper; + ImageRevealHelper.RevealStateListener mRevealStateListener; + + @Before + public void setUp() throws Exception { + mRevealStateListener = new ImageRevealHelper.RevealStateListener() { + @Override + public void onRevealStateChanged() { + // no-op + } + + @Override + public void onRevealStart(boolean animate) { + // no-op + } + + @Override + public void onRevealEnd() { + // no-op + } + }; + mImageRevealHelper = new ImageRevealHelper(mRevealStateListener); + } + + @Test + public void testBiometricAuthUnlockAnimateImageRevealState_shouldNotBlackoutScreen() { + assertThat(mImageRevealHelper.getReveal()).isEqualTo(0f); + + mImageRevealHelper.updateAwake(true /* awake */, ANIMATION_DURATION); + assertThat(mImageRevealHelper.getReveal()).isEqualTo(0f); + + // When device unlock through Biometric, should not show reveal transition + mImageRevealHelper.updateAwake(false /* awake */, 0); + assertThat(mImageRevealHelper.getReveal()).isEqualTo(1f); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java index 378bba1afda3..1e8ebeafce8a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java @@ -48,7 +48,7 @@ public class SysuiLogTest extends SysuiTestCase { @Test public void testLogDisabled_noLogsWritten() { - mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, false); + mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, false, false); assertEquals(mSysuiLog.mTimeline, null); mSysuiLog.log(new Event("msg")); @@ -57,7 +57,7 @@ public class SysuiLogTest extends SysuiTestCase { @Test public void testLogEnabled_logWritten() { - mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true); + mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true, false); assertEquals(mSysuiLog.mTimeline.size(), 0); mSysuiLog.log(new Event("msg")); @@ -66,7 +66,7 @@ public class SysuiLogTest extends SysuiTestCase { @Test public void testMaxLogs() { - mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true); + mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true, false); assertEquals(mSysuiLog.mTimeline.size(), 0); final String msg = "msg"; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java index 39ce8c1209ac..8a9a7a28efb7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java @@ -120,7 +120,6 @@ public class TileQueryHelperTest extends SysuiTestCase { ).when(mQSTileHost).createTile(anyString()); FakeSystemClock clock = new FakeSystemClock(); - clock.setAutoIncrement(false); mMainExecutor = new FakeExecutor(clock); mBgExecutor = new FakeExecutor(clock); mTileQueryHelper = new TileQueryHelper(mContext, mMainExecutor, mBgExecutor); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java index a754a00df940..8aac1891a5e4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java @@ -30,7 +30,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyH import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.phone.ShadeController; +import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.google.android.collect.Sets; @@ -76,7 +76,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { mRemoteInputManager = new TestableNotificationRemoteInputManager(mContext, mLockscreenUserManager, mSmartReplyController, mEntryManager, - () -> mock(ShadeController.class), + () -> mock(StatusBar.class), mStateController, Handler.createAsync(Looper.myLooper()), mRemoteInputUriController); @@ -212,12 +212,12 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { NotificationLockscreenUserManager lockscreenUserManager, SmartReplyController smartReplyController, NotificationEntryManager notificationEntryManager, - Lazy<ShadeController> shadeController, + Lazy<StatusBar> statusBarLazy, StatusBarStateController statusBarStateController, Handler mainHandler, RemoteInputUriController remoteInputUriController) { super(context, lockscreenUserManager, smartReplyController, notificationEntryManager, - shadeController, statusBarStateController, mainHandler, + statusBarLazy, statusBarStateController, mainHandler, remoteInputUriController); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java index 95ce53c58e95..3f624128ac2c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java @@ -41,7 +41,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.phone.ShadeController; +import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.RemoteInputUriController; import org.junit.Before; @@ -88,7 +88,7 @@ public class SmartReplyControllerTest extends SysuiTestCase { mRemoteInputManager = new NotificationRemoteInputManager(mContext, mock(NotificationLockscreenUserManager.class), mSmartReplyController, - mNotificationEntryManager, () -> mock(ShadeController.class), + mNotificationEntryManager, () -> mock(StatusBar.class), mStatusBarStateController, Handler.createAsync(Looper.myLooper()), mRemoteInputUriController); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java index 68730d12dee3..7fabb0fee8e2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java @@ -100,7 +100,7 @@ public class NotificationFilterTest extends SysuiTestCase { when(mEnvironment.isDeviceProvisioned()).thenReturn(true); when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); mRow = new NotificationTestHelper(getContext(), mDependency).createRow(); - mNotificationFilter = new NotificationFilter(); + mNotificationFilter = new NotificationFilter(mock(StatusBarStateController.class)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java index a25af84ca28e..ffaea156c9d5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java @@ -690,7 +690,6 @@ public class NotifListBuilderImplTest extends SysuiTestCase { mListBuilder.addFilter(filter3); // GIVEN the SystemClock is set to a particular time: - mSystemClock.setAutoIncrement(true); mSystemClock.setUptimeMillis(47); // WHEN the pipeline is kicked off on a list of notifs diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 61e5058b1a20..b27e84a37e3f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -126,7 +126,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Test public void showBouncer_onlyWhenShowing() { mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */); - mStatusBar.showBouncer(true /* scrimmed */); + mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */); verify(mBouncer, never()).show(anyBoolean(), anyBoolean()); verify(mBouncer, never()).show(anyBoolean()); } @@ -135,7 +135,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { public void showBouncer_notWhenBouncerAlreadyShowing() { mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */); when(mBouncer.isSecure()).thenReturn(true); - mStatusBar.showBouncer(true /* scrimmed */); + mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */); verify(mBouncer, never()).show(anyBoolean(), anyBoolean()); verify(mBouncer, never()).show(anyBoolean()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 77cdc025bbc9..d7c00cf3038d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -98,6 +98,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { @Mock private StatusBarStateController mStatusBarStateController; @Mock + private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private RemoteInputController mRemoteInputController; @@ -167,7 +169,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { getContext(), mock(CommandQueue.class), () -> mAssistManager, mEntryManager, mock(HeadsUpManagerPhone.class), mActivityStarter, mStatusBarService, - mock(StatusBarStateController.class), mock(KeyguardManager.class), + mock(StatusBarStateController.class), mStatusBarKeyguardViewManager, + mock(KeyguardManager.class), mock(IDreamManager.class), mRemoteInputManager, mock(StatusBarRemoteInputCallback.class), mock(NotificationGroupManager.class), mock(NotificationLockscreenUserManager.class), @@ -186,7 +189,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { // set up addAfterKeyguardGoneRunnable to synchronously invoke the Runnable arg doAnswer(answerVoid(Runnable::run)) - .when(mStatusBar).addAfterKeyguardGoneRunnable(any(Runnable.class)); + .when(mStatusBarKeyguardViewManager) + .addAfterKeyguardGoneRunnable(any(Runnable.class)); // set up addPostCollapseAction to synchronously invoke the Runnable arg doAnswer(answerVoid(Runnable::run)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index 14f5795c39f1..fb6e1684c376 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -39,6 +39,7 @@ import com.android.systemui.InitController; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.NotificationEntryBuilder; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; @@ -113,6 +114,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class), mock(NotificationAlertingManager.class), mock(NotificationRowBinderImpl.class), mock(KeyguardStateController.class), + mock(KeyguardIndicationController.class), mStatusBar, mCommandQueue); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java index 9d76b425725f..6dfd0828de9a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java @@ -54,6 +54,7 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager; @Mock private KeyguardStateController mKeyguardStateController; @Mock private SysuiStatusBarStateController mStatusBarStateController; + @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock private ActivityStarter mActivityStarter; private int mCurrentUserId = 0; @@ -71,8 +72,8 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { mRemoteInputCallback = spy(new StatusBarRemoteInputCallback(mContext, mock(NotificationGroupManager.class), mNotificationLockscreenUserManager, - mKeyguardStateController, mStatusBarStateController, mActivityStarter, - () -> mShadeController, new CommandQueue(mContext))); + mKeyguardStateController, mStatusBarStateController, mStatusBarKeyguardViewManager, + mActivityStarter, () -> mShadeController, new CommandQueue(mContext))); mRemoteInputCallback.mChallengeReceiver = mRemoteInputCallback.new ChallengeReceiver(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java index 529333effa2c..00ea18749de3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java @@ -80,7 +80,7 @@ public class StatusBarWindowViewTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mView = new StatusBarWindowView(getContext(), null); - when(mStatusBar.isDozing()).thenReturn(false); + when(mStatusBarStateController.isDozing()).thenReturn(false); mDependency.injectTestDependency(ShadeController.class, mShadeController); when(mDockManager.isDocked()).thenReturn(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java index 3ed6c5b2b11b..f3c053058468 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java @@ -168,11 +168,6 @@ public class FakeExecutor implements DelayableExecutor { executeDelayed(command, 0); } - @Override - public void removeAll() { - mQueuedRunnables.clear(); - } - /** * Run all Executors in a loop until they all report they have no ready work to do. * diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java index 7fd694244afa..bd641243be12 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java @@ -49,7 +49,6 @@ public class FakeExecutorTest extends SysuiTestCase { @Test public void testNoDelay() { FakeSystemClock clock = new FakeSystemClock(); - clock.setAutoIncrement(false); FakeExecutor fakeExecutor = new FakeExecutor(clock); RunnableImpl runnable = new RunnableImpl(); @@ -99,7 +98,6 @@ public class FakeExecutorTest extends SysuiTestCase { @Test public void testDelayed() { FakeSystemClock clock = new FakeSystemClock(); - clock.setAutoIncrement(false); FakeExecutor fakeExecutor = new FakeExecutor(clock); RunnableImpl runnable = new RunnableImpl(); @@ -134,7 +132,6 @@ public class FakeExecutorTest extends SysuiTestCase { @Test public void testDelayed_AdvanceAndRun() { FakeSystemClock clock = new FakeSystemClock(); - clock.setAutoIncrement(false); FakeExecutor fakeExecutor = new FakeExecutor(clock); RunnableImpl runnable = new RunnableImpl(); @@ -181,7 +178,6 @@ public class FakeExecutorTest extends SysuiTestCase { @Test public void testExecutionOrder() { FakeSystemClock clock = new FakeSystemClock(); - clock.setAutoIncrement(false); FakeExecutor fakeExecutor = new FakeExecutor(clock); RunnableImpl runnableA = new RunnableImpl(); RunnableImpl runnableB = new RunnableImpl(); @@ -251,7 +247,6 @@ public class FakeExecutorTest extends SysuiTestCase { @Test public void testRemoval_single() { FakeSystemClock clock = new FakeSystemClock(); - clock.setAutoIncrement(false); FakeExecutor fakeExecutor = new FakeExecutor(clock); RunnableImpl runnable = new RunnableImpl(); Runnable removeFunction; @@ -291,7 +286,6 @@ public class FakeExecutorTest extends SysuiTestCase { @Test public void testRemoval_multi() { FakeSystemClock clock = new FakeSystemClock(); - clock.setAutoIncrement(false); FakeExecutor fakeExecutor = new FakeExecutor(clock); List<Runnable> removeFunctions = new ArrayList<>(); RunnableImpl runnable = new RunnableImpl(); @@ -325,36 +319,6 @@ public class FakeExecutorTest extends SysuiTestCase { assertEquals(1, runnable.mRunCount); } - /** - * Test removing everything - */ - @Test - public void testRemoval_all() { - FakeSystemClock clock = new FakeSystemClock(); - clock.setAutoIncrement(false); - FakeExecutor fakeExecutor = new FakeExecutor(clock); - RunnableImpl runnable = new RunnableImpl(); - - // Nothing to remove. - assertEquals(0, runnable.mRunCount); - assertEquals(0, fakeExecutor.numPending()); - - // Two pending items that have not yet run. - fakeExecutor.executeDelayed(runnable, 100); - fakeExecutor.executeDelayed(runnable, 200); - assertEquals(2, fakeExecutor.numPending()); - assertEquals(0, runnable.mRunCount); - - // Remove the items. - fakeExecutor.removeAll(); - - // Nothing to run - fakeExecutor.advanceClockToLast(); - assertEquals(0, fakeExecutor.runAllReady()); - assertEquals(0, fakeExecutor.numPending()); - assertEquals(0, runnable.mRunCount); - } - private static class RunnableImpl implements Runnable { int mRunCount; diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java b/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java index 65e5902c84df..e94eaafdb692 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java @@ -20,8 +20,6 @@ import java.util.ArrayList; import java.util.List; public class FakeSystemClock implements SystemClock { - private boolean mAutoIncrement = true; - private long mUptimeMillis; private long mElapsedRealtime; private long mElapsedRealtimeNanos; @@ -34,54 +32,36 @@ public class FakeSystemClock implements SystemClock { @Override public long uptimeMillis() { long value = mUptimeMillis; - if (mAutoIncrement) { - setUptimeMillis(mUptimeMillis + 1); - } return value; } @Override public long elapsedRealtime() { long value = mElapsedRealtime; - if (mAutoIncrement) { - setElapsedRealtime(mElapsedRealtime + 1); - } return value; } @Override public long elapsedRealtimeNanos() { long value = mElapsedRealtimeNanos; - if (mAutoIncrement) { - setElapsedRealtimeNanos(mElapsedRealtimeNanos + 1); - } return value; } @Override public long currentThreadTimeMillis() { long value = mCurrentThreadTimeMillis; - if (mAutoIncrement) { - setCurrentThreadTimeMillis(mCurrentThreadTimeMillis + 1); - } return value; } @Override public long currentThreadTimeMicro() { long value = mCurrentThreadTimeMicro; - if (mAutoIncrement) { - setCurrentThreadTimeMicro(mCurrentThreadTimeMicro + 1); - } return value; } @Override public long currentTimeMicro() { long value = mCurrentTimeMicro; - if (mAutoIncrement) { - setCurrentTimeMicro(mCurrentTimeMicro + 1); - } return value; } @@ -127,11 +107,6 @@ public class FakeSystemClock implements SystemClock { } } - /** If true, each call to get____ will be one higher than the previous call to that method. */ - public void setAutoIncrement(boolean autoIncrement) { - mAutoIncrement = autoIncrement; - } - public void addListener(ClockTickListener listener) { mListeners.add(listener); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/EventsTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/EventsTest.java new file mode 100644 index 000000000000..701b2fab5f85 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/EventsTest.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume; + +import static org.junit.Assert.assertEquals; + +import android.media.AudioManager; +import android.media.AudioSystem; +import android.metrics.LogMaker; +import android.provider.Settings; + +import androidx.test.filters.SmallTest; + +import com.android.internal.logging.UiEventLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.logging.testing.FakeMetricsLogger; +import com.android.internal.logging.testing.UiEventLoggerFake; +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Queue; + +/** + * Parameterized unit test for Events.logEvent. + * + * This test captures a translation table between the Event class tags, the debugging logs, + * the event-buffer logs, and the statsd logs. + * + * This test works as a straight JUnit4 test, but is declared as a SysuiTestCase because + * AAAPlusPlusVerifySysuiRequiredTestPropertiesTest requires all tests in SystemUiTest extend + * either SysuiTestCase or SysUiBaseFragmentTest. + * + */ +@RunWith(Parameterized.class) +@SmallTest +public class EventsTest extends SysuiTestCase { + private FakeMetricsLogger mLegacyLogger; + private UiEventLoggerFake mUiEventLogger; + + @Before + public void setFakeLoggers() { + mLegacyLogger = new FakeMetricsLogger(); + Events.sLegacyLogger = mLegacyLogger; + mUiEventLogger = new UiEventLoggerFake(); + Events.sUiEventLogger = mUiEventLogger; + } + + // Parameters for calling writeEvent with arbitrary args. + @Parameterized.Parameter + public int mTag; + + @Parameterized.Parameter(1) + public Object[] mArgs; + + // Expect returned string exactly matches. + @Parameterized.Parameter(2) + public String mExpectedMessage; + + // Expect these MetricsLogger calls. + + @Parameterized.Parameter(3) + public int[] mExpectedMetrics; + + // Expect this UiEvent (use null if there isn't one). + @Parameterized.Parameter(4) + public UiEventLogger.UiEventEnum mUiEvent; + + @Test + public void testLogEvent() { + String result = Events.logEvent(mTag, mArgs); + assertEquals("Show Dialog", mExpectedMessage, result); + + Queue<LogMaker> logs = mLegacyLogger.getLogs(); + if (mExpectedMetrics == null) { + assertEquals(0, logs.size()); + } else { + assertEquals(mExpectedMetrics.length, logs.size()); + if (mExpectedMetrics.length > 0) { + assertEquals(mExpectedMetrics[0], logs.remove().getCategory()); + } + if (mExpectedMetrics.length > 1) { + assertEquals(mExpectedMetrics[1], logs.remove().getCategory()); + } + } + Queue<UiEventLoggerFake.FakeUiEvent> events = mUiEventLogger.getLogs(); + if (mUiEvent != null) { + assertEquals(mUiEvent.getId(), events.remove().eventId); + } + } + + @Parameterized.Parameters(name = "{index}: {2}") + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][]{ + {Events.EVENT_SETTINGS_CLICK, null, + "writeEvent settings_click", + new int[]{MetricsEvent.ACTION_VOLUME_SETTINGS}, + Events.VolumeDialogEvent.VOLUME_DIALOG_SETTINGS_CLICK}, + {Events.EVENT_SHOW_DIALOG, new Object[]{Events.SHOW_REASON_VOLUME_CHANGED, false}, + "writeEvent show_dialog volume_changed keyguard=false", + new int[]{MetricsEvent.VOLUME_DIALOG, + MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM}, + Events.VolumeDialogOpenEvent.VOLUME_DIALOG_SHOW_VOLUME_CHANGED}, + {Events.EVENT_EXPAND, new Object[]{true}, + "writeEvent expand true", + new int[]{MetricsEvent.VOLUME_DIALOG_DETAILS}, + Events.VolumeDialogEvent.VOLUME_DIALOG_EXPAND_DETAILS}, + {Events.EVENT_DISMISS_DIALOG, + new Object[]{Events.DISMISS_REASON_TOUCH_OUTSIDE, true}, + "writeEvent dismiss_dialog touch_outside", + new int[]{MetricsEvent.VOLUME_DIALOG}, + Events.VolumeDialogCloseEvent.VOLUME_DIALOG_DISMISS_TOUCH_OUTSIDE}, + {Events.EVENT_ACTIVE_STREAM_CHANGED, new Object[]{AudioSystem.STREAM_ACCESSIBILITY}, + "writeEvent active_stream_changed STREAM_ACCESSIBILITY", + new int[]{MetricsEvent.ACTION_VOLUME_STREAM}, + Events.VolumeDialogEvent.VOLUME_DIALOG_ACTIVE_STREAM_CHANGED}, + {Events.EVENT_ICON_CLICK, + new Object[]{AudioSystem.STREAM_MUSIC, Events.ICON_STATE_MUTE}, + "writeEvent icon_click STREAM_MUSIC mute", + new int[]{MetricsEvent.ACTION_VOLUME_ICON}, + Events.VolumeDialogEvent.VOLUME_DIALOG_MUTE_STREAM}, + {Events.EVENT_TOUCH_LEVEL_DONE, + new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 0}, + "writeEvent touch_level_done STREAM_MUSIC 0", + new int[]{MetricsEvent.ACTION_VOLUME_SLIDER}, + Events.VolumeDialogEvent.VOLUME_DIALOG_SLIDER_TO_ZERO}, + {Events.EVENT_TOUCH_LEVEL_DONE, + new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 1}, + "writeEvent touch_level_done STREAM_MUSIC 1", + new int[]{MetricsEvent.ACTION_VOLUME_SLIDER}, + Events.VolumeDialogEvent.VOLUME_DIALOG_SLIDER}, + {Events.EVENT_TOUCH_LEVEL_CHANGED, + new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 0}, + "writeEvent touch_level_changed STREAM_MUSIC 0", + null, null}, + {Events.EVENT_LEVEL_CHANGED, + new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 0}, + "writeEvent level_changed STREAM_MUSIC 0", + null, null}, + {Events.EVENT_MUTE_CHANGED, + new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 0}, + "writeEvent mute_changed STREAM_MUSIC 0", + null, null}, + {Events.EVENT_KEY, + new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 0}, + "writeEvent key STREAM_MUSIC 0", + new int[]{MetricsEvent.ACTION_VOLUME_KEY}, + Events.VolumeDialogEvent.VOLUME_KEY_TO_ZERO}, + {Events.EVENT_KEY, + new Object[]{AudioSystem.STREAM_MUSIC, /* volume */ 1}, + "writeEvent key STREAM_MUSIC 1", + new int[]{MetricsEvent.ACTION_VOLUME_KEY}, + Events.VolumeDialogEvent.VOLUME_KEY}, + {Events.EVENT_RINGER_TOGGLE, new Object[]{AudioManager.RINGER_MODE_NORMAL}, + "writeEvent ringer_toggle normal", + new int[]{MetricsEvent.ACTION_VOLUME_RINGER_TOGGLE}, + Events.VolumeDialogEvent.RINGER_MODE_NORMAL}, + {Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED, + new Object[]{AudioManager.RINGER_MODE_NORMAL}, + "writeEvent external_ringer_mode_changed normal", + new int[]{MetricsEvent.ACTION_RINGER_MODE}, + null}, + {Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, + new Object[]{AudioManager.RINGER_MODE_NORMAL}, + "writeEvent internal_ringer_mode_changed normal", + null, null}, + {Events.EVENT_ZEN_MODE_CHANGED, + new Object[]{Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS}, + "writeEvent zen_mode_changed important_interruptions", + null, Events.ZenModeEvent.ZEN_MODE_IMPORTANT_ONLY}, + {Events.EVENT_ZEN_MODE_CHANGED, + new Object[]{Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS}, + "writeEvent zen_mode_changed important_interruptions", + null, Events.ZenModeEvent.ZEN_MODE_IMPORTANT_ONLY}, + {Events.EVENT_SUPPRESSOR_CHANGED, + new Object[]{"component", "name"}, + "writeEvent suppressor_changed component name", + null, null}, + {Events.EVENT_SHOW_USB_OVERHEAT_ALARM, + new Object[]{Events.SHOW_REASON_USB_OVERHEAD_ALARM_CHANGED, true}, + "writeEvent show_usb_overheat_alarm usb_temperature_above_threshold " + + "keyguard=true", + new int[]{MetricsEvent.POWER_OVERHEAT_ALARM, + MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM}, + Events.VolumeDialogEvent.USB_OVERHEAT_ALARM}, + {Events.EVENT_DISMISS_USB_OVERHEAT_ALARM, + new Object[]{Events.DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED, true}, + "writeEvent dismiss_usb_overheat_alarm usb_temperature_below_threshold " + + "keyguard=true", + new int[]{MetricsEvent.POWER_OVERHEAT_ALARM, + MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM}, + Events.VolumeDialogEvent.USB_OVERHEAT_ALARM_DISMISSED}, + }); + } +} + diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 7e8721d3cc70..3c953b348ed9 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -31,6 +31,7 @@ java_defaults { "android.hardware.tetheroffload.control-V1.0-java", "tethering-client", ], + libs: ["unsupportedappusage"], manifest: "AndroidManifestBase.xml", } diff --git a/packages/Tethering/apex/manifest.json b/packages/Tethering/apex/manifest.json index 3fb62f3405a3..078302ac51a4 100644 --- a/packages/Tethering/apex/manifest.json +++ b/packages/Tethering/apex/manifest.json @@ -1,4 +1,4 @@ { "name": "com.android.tethering.apex", - "version": 290000000 + "version": 300000000 } diff --git a/services/Android.bp b/services/Android.bp index 3b566078bd51..fd4094f2a7c2 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -14,6 +14,7 @@ filegroup { ":services.appwidget-sources", ":services.autofill-sources", ":services.backup-sources", + ":backuplib-sources", ":services.companion-sources", ":services.contentcapture-sources", ":services.contentsuggestions-sources", @@ -101,3 +102,29 @@ filegroup { name: "art-profile", srcs: ["art-profile"], } + +// API stub +// ============================================================= + +droidstubs { + name: "services-stubs.sources", + srcs: [":services-sources"], + installable: false, + // TODO: remove the --hide options below + args: " --show-single-annotation android.annotation.SystemApi" + + " --hide-annotation android.annotation.Hide" + + " --hide-package com.google.android.startop.iorap" + + " --hide ReferencesHidden" + + " --hide DeprecationMismatch" + + " --hide HiddenTypedefConstant", + libs: [ + "framework-all", + ], + visibility: ["//visibility:private"], +} + +java_library { + name: "services-stubs", + srcs: [":services-stubs.sources"], + installable: false, +} diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 7fdd83bebbcd..6a6e2b2f3467 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -16,6 +16,11 @@ package com.android.server.accessibility; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; +import static android.view.accessibility.AccessibilityManager.ShortcutType; + +import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.android.internal.util.FunctionalUtils.ignoreRemoteException; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; @@ -31,6 +36,7 @@ import android.app.ActivityOptions; import android.app.AlertDialog; import android.app.PendingIntent; import android.appwidget.AppWidgetManagerInternal; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -70,6 +76,7 @@ import android.provider.Settings; import android.provider.SettingsStringUtil.SettingStringHelper; import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; +import android.util.ArraySet; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; @@ -113,9 +120,9 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.function.Consumer; +import java.util.function.Function; /** * This class is instantiated by the system as a system level service and can be @@ -754,6 +761,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub userState.setTouchExplorationEnabledLocked(touchExplorationEnabled); userState.setDisplayMagnificationEnabledLocked(false); userState.setNavBarMagnificationEnabledLocked(false); + userState.disableShortcutMagnificationLocked(); + userState.setAutoclickEnabledLocked(false); userState.mEnabledServices.clear(); userState.mEnabledServices.add(service); @@ -1072,6 +1081,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } + // TODO(a11y shortcut): Remove this function and Use #performAccessibilityShortcutInternal( + // ACCESSIBILITY_BUTTON) instead, after the new Settings shortcut Ui merged. private void notifyAccessibilityButtonClickedLocked(int displayId) { final AccessibilityUserState state = getCurrentUserStateLocked(); @@ -1105,8 +1116,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (state.getServiceAssignedToAccessibilityButtonLocked() == null && !state.isNavBarMagnificationAssignedToAccessibilityButtonLocked()) { mMainHandler.sendMessage(obtainMessage( - AccessibilityManagerService::showAccessibilityButtonTargetSelection, this, - displayId)); + AccessibilityManagerService::showAccessibilityTargetsSelection, this, + displayId, ACCESSIBILITY_BUTTON)); } else if (state.isNavBarMagnificationEnabledLocked() && state.isNavBarMagnificationAssignedToAccessibilityButtonLocked()) { mMainHandler.sendMessage(obtainMessage( @@ -1125,8 +1136,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } // The user may have turned off the assigned service or feature mMainHandler.sendMessage(obtainMessage( - AccessibilityManagerService::showAccessibilityButtonTargetSelection, this, - displayId)); + AccessibilityManagerService::showAccessibilityTargetsSelection, this, + displayId, ACCESSIBILITY_BUTTON)); } } @@ -1138,13 +1149,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } - private void showAccessibilityButtonTargetSelection(int displayId) { + private void showAccessibilityTargetsSelection(int displayId, + @ShortcutType int shortcutType) { Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(); + bundle.putInt(AccessibilityManager.EXTRA_SHORTCUT_TYPE, shortcutType); mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId)); } + private void launchShortcutTargetActivity(int displayId, ComponentName name) { + final Intent intent = new Intent(); + final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(); + intent.setComponent(name); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + try { + mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId)); + } catch (ActivityNotFoundException ignore) { + // ignore the exception + } + } + private void notifyAccessibilityButtonVisibilityChangedLocked(boolean available) { final AccessibilityUserState state = getCurrentUserStateLocked(); mIsAccessibilityButtonShown = available; @@ -1353,9 +1378,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub */ private void readComponentNamesFromSettingLocked(String settingName, int userId, Set<ComponentName> outComponentNames) { - String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), - settingName, userId); - readComponentNamesFromStringLocked(settingValue, outComponentNames, false); + readColonDelimitedSettingToSet(settingName, userId, outComponentNames, + str -> ComponentName.unflattenFromString(str)); } /** @@ -1370,34 +1394,57 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private void readComponentNamesFromStringLocked(String names, Set<ComponentName> outComponentNames, boolean doMerge) { + readColonDelimitedStringToSet(names, outComponentNames, doMerge, + str -> ComponentName.unflattenFromString(str)); + } + + @Override + public void persistComponentNamesToSettingLocked(String settingName, + Set<ComponentName> componentNames, int userId) { + persistColonDelimitedSetToSettingLocked(settingName, userId, componentNames, + componentName -> componentName.flattenToShortString()); + } + + private <T> void readColonDelimitedSettingToSet(String settingName, int userId, Set<T> outSet, + Function<String, T> toItem) { + final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), + settingName, userId); + readColonDelimitedStringToSet(settingValue, outSet, false, toItem); + } + + private <T> void readColonDelimitedStringToSet(String names, Set<T> outSet, boolean doMerge, + Function<String, T> toItem) { if (!doMerge) { - outComponentNames.clear(); + outSet.clear(); } - if (names != null) { - TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; + if (!TextUtils.isEmpty(names)) { + final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; splitter.setString(names); while (splitter.hasNext()) { - String str = splitter.next(); - if (str == null || str.length() <= 0) { + final String str = splitter.next(); + if (TextUtils.isEmpty(str)) { continue; } - ComponentName enabledService = ComponentName.unflattenFromString(str); - if (enabledService != null) { - outComponentNames.add(enabledService); + final T item = toItem.apply(str); + if (item != null) { + outSet.add(item); } } } } - @Override - public void persistComponentNamesToSettingLocked(String settingName, - Set<ComponentName> componentNames, int userId) { - StringBuilder builder = new StringBuilder(); - for (ComponentName componentName : componentNames) { + private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId, + Set<T> set, Function<T, String> toString) { + final StringBuilder builder = new StringBuilder(); + for (T item : set) { + final String str = (item != null ? toString.apply(item) : null); + if (TextUtils.isEmpty(str)) { + continue; + } if (builder.length() > 0) { builder.append(COMPONENT_NAME_SEPARATOR); } - builder.append(componentName.flattenToShortString()); + builder.append(str); } final long identity = Binder.clearCallingIdentity(); try { @@ -1537,7 +1584,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (userState.isDisplayMagnificationEnabledLocked()) { flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER; } - if (userState.isNavBarMagnificationEnabledLocked()) { + if (userState.isNavBarMagnificationEnabledLocked() + || userState.isShortcutKeyMagnificationEnabledLocked()) { flags |= AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER; } if (userHasMagnificationServicesLocked(userState)) { @@ -1647,7 +1695,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mInitialized = true; updateLegacyCapabilitiesLocked(userState); updateServicesLocked(userState); - updateAccessibilityShortcutLocked(userState); updateWindowsForAccessibilityCallbackLocked(userState); updateFilterKeyEventsLocked(userState); updateTouchExplorationLocked(userState); @@ -1657,6 +1704,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub scheduleUpdateInputFilter(userState); updateRelevantEventsLocked(userState); scheduleUpdateClientsIfNeededLocked(userState); + updateAccessibilityShortcutKeyTargetsLocked(userState); updateAccessibilityButtonTargetsLocked(userState); } @@ -1751,7 +1799,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub somethingChanged |= readHighTextContrastEnabledSettingLocked(userState); somethingChanged |= readMagnificationEnabledSettingsLocked(userState); somethingChanged |= readAutoclickEnabledSettingLocked(userState); - somethingChanged |= readAccessibilityShortcutSettingLocked(userState); + somethingChanged |= readAccessibilityShortcutKeySettingLocked(userState); somethingChanged |= readAccessibilityButtonSettingsLocked(userState); somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState); return somethingChanged; @@ -1847,57 +1895,43 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } - private boolean readAccessibilityShortcutSettingLocked(AccessibilityUserState userState) { - String componentNameToEnableString = AccessibilityShortcutController - .getTargetServiceComponentNameString(mContext, userState.mUserId); - if ((componentNameToEnableString == null) || componentNameToEnableString.isEmpty()) { - if (userState.getServiceToEnableWithShortcutLocked() == null) { - return false; + private boolean readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState) { + final Set<String> targetsFromSetting = new ArraySet<>(); + readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, + userState.mUserId, targetsFromSetting, str -> str); + if (targetsFromSetting.isEmpty()) { + // Fall back to device's default a11y service. + final String defaultService = mContext.getString( + R.string.config_defaultAccessibilityService); + if (!TextUtils.isEmpty(defaultService)) { + targetsFromSetting.add(defaultService); } - userState.setServiceToEnableWithShortcutLocked(null); - return true; } - ComponentName componentNameToEnable = - ComponentName.unflattenFromString(componentNameToEnableString); - if ((componentNameToEnable != null) - && componentNameToEnable.equals(userState.getServiceToEnableWithShortcutLocked())) { + + final Set<String> currentTargets = + userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY); + if (targetsFromSetting.equals(currentTargets)) { return false; } - - userState.setServiceToEnableWithShortcutLocked(componentNameToEnable); + currentTargets.clear(); + currentTargets.addAll(targetsFromSetting); scheduleNotifyClientsOfServicesStateChangeLocked(userState); return true; } private boolean readAccessibilityButtonSettingsLocked(AccessibilityUserState userState) { - String componentId = Settings.Secure.getStringForUser(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, userState.mUserId); - if (TextUtils.isEmpty(componentId)) { - if ((userState.getServiceAssignedToAccessibilityButtonLocked() == null) - && !userState.isNavBarMagnificationAssignedToAccessibilityButtonLocked()) { - return false; - } - userState.setServiceAssignedToAccessibilityButtonLocked(null); - userState.setNavBarMagnificationAssignedToAccessibilityButtonLocked(false); - return true; - } - - if (componentId.equals(MagnificationController.class.getName())) { - if (userState.isNavBarMagnificationAssignedToAccessibilityButtonLocked()) { - return false; - } - userState.setServiceAssignedToAccessibilityButtonLocked(null); - userState.setNavBarMagnificationAssignedToAccessibilityButtonLocked(true); - return true; - } + final Set<String> targetsFromSetting = new ArraySet<>(); + readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, + userState.mUserId, targetsFromSetting, str -> str); - ComponentName componentName = ComponentName.unflattenFromString(componentId); - if (Objects.equals(componentName, - userState.getServiceAssignedToAccessibilityButtonLocked())) { + final Set<String> currentTargets = + userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON); + if (targetsFromSetting.equals(currentTargets)) { return false; } - userState.setServiceAssignedToAccessibilityButtonLocked(componentName); - userState.setNavBarMagnificationAssignedToAccessibilityButtonLocked(false); + currentTargets.clear(); + currentTargets.addAll(targetsFromSetting); + scheduleNotifyClientsOfServicesStateChangeLocked(userState); return true; } @@ -1921,34 +1955,33 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } /** - * Check if the service that will be enabled by the shortcut is installed. If it isn't, - * clear the value and the associated setting so a sideloaded service can't spoof the - * package name of the default service. - * - * @param userState + * Check if the targets that will be enabled by the accessibility shortcut key is installed. + * If it isn't, remove it from the list and associated setting so a side loaded service can't + * spoof the package name of the default service. */ - private void updateAccessibilityShortcutLocked(AccessibilityUserState userState) { - if (userState.getServiceToEnableWithShortcutLocked() == null) { + private void updateAccessibilityShortcutKeyTargetsLocked(AccessibilityUserState userState) { + final Set<String> currentTargets = + userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY); + final int lastSize = currentTargets.size(); + if (lastSize == 0) { return; } - boolean shortcutServiceIsInstalled = - AccessibilityShortcutController.getFrameworkShortcutFeaturesMap() - .containsKey(userState.getServiceToEnableWithShortcutLocked()); - for (int i = 0; !shortcutServiceIsInstalled && (i < userState.mInstalledServices.size()); - i++) { - if (userState.mInstalledServices.get(i).getComponentName() - .equals(userState.getServiceToEnableWithShortcutLocked())) { - shortcutServiceIsInstalled = true; - } + currentTargets.removeIf( + name -> !userState.isShortcutTargetInstalledLocked(name)); + if (lastSize == currentTargets.size()) { + return; } - if (!shortcutServiceIsInstalled) { - userState.setServiceToEnableWithShortcutLocked(null); + + // Update setting key with new value. + persistColonDelimitedSetToSettingLocked( + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, + userState.mUserId, currentTargets, str -> str); + scheduleNotifyClientsOfServicesStateChangeLocked(userState); + + // Disable accessibility shortcut key if there's no shortcut installed. + if (currentTargets.isEmpty()) { final long identity = Binder.clearCallingIdentity(); try { - Settings.Secure.putStringForUser(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null, - userState.mUserId); - Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0, userState.mUserId); } finally { @@ -2004,7 +2037,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // displays in one display. It's not a real display and there's no input events for it. final ArrayList<Display> displays = getValidDisplayList(); if (userState.isDisplayMagnificationEnabledLocked() - || userState.isNavBarMagnificationEnabledLocked()) { + || userState.isNavBarMagnificationEnabledLocked() + || userState.isShortcutKeyMagnificationEnabledLocked()) { for (int i = 0; i < displays.size(); i++) { final Display display = displays.get(i); getMagnificationController().register(display.getDisplayId()); @@ -2088,7 +2122,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } + /** + * 1) Update accessibility button availability to accessibility services. + * 2) Check if the targets that will be enabled by the accessibility button is installed. + * If it isn't, remove it from the list and associated setting so a side loaded service can't + * spoof the package name of the default service. + */ private void updateAccessibilityButtonTargetsLocked(AccessibilityUserState userState) { + // Update accessibility button availability. for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { final AccessibilityServiceConnection service = userState.mBoundServices.get(i); if (service.mRequestAccessibilityButton) { @@ -2096,6 +2137,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub service.isAccessibilityButtonAvailableLocked(userState)); } } + + final Set<String> currentTargets = + userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON); + final int lastSize = currentTargets.size(); + if (lastSize == 0) { + return; + } + currentTargets.removeIf( + name -> !userState.isShortcutTargetInstalledLocked(name)); + if (lastSize == currentTargets.size()) { + return; + } + + // Update setting key with new value. + persistColonDelimitedSetToSettingLocked( + Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, + userState.mUserId, currentTargets, str -> str); + scheduleNotifyClientsOfServicesStateChangeLocked(userState); } private void updateRecommendedUiTimeoutLocked(AccessibilityUserState userState) { @@ -2156,7 +2215,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } /** - * AIDL-exposed method to be called when the accessibility shortcut is enabled. Requires + * AIDL-exposed method to be called when the accessibility shortcut key is enabled. Requires * permission to write secure settings, since someone with that permission can enable * accessibility services themselves. */ @@ -2168,52 +2227,177 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub throw new SecurityException( "performAccessibilityShortcut requires the MANAGE_ACCESSIBILITY permission"); } + mMainHandler.sendMessage(obtainMessage( + AccessibilityManagerService::performAccessibilityShortcutInternal, this, + Display.DEFAULT_DISPLAY, ACCESSIBILITY_SHORTCUT_KEY)); + } + + /** + * Perform the accessibility shortcut action. + * + * @param shortcutType The shortcut type. + * @param displayId The display id of the accessibility button. + */ + private void performAccessibilityShortcutInternal(int displayId, + @ShortcutType int shortcutType) { + final List<String> shortcutTargets = getAccessibilityShortcutTargetsInternal(shortcutType); + if (shortcutTargets.isEmpty()) { + Slog.d(LOG_TAG, "No target to perform shortcut, shortcutType=" + shortcutType); + return; + } + // In case there are many targets assigned to the given shortcut. + if (shortcutTargets.size() > 1) { + showAccessibilityTargetsSelection(displayId, shortcutType); + return; + } + final String targetName = shortcutTargets.get(0); + // In case user assigned magnification to the given shortcut. + if (targetName.equals(MAGNIFICATION_CONTROLLER_NAME)) { + sendAccessibilityButtonToInputFilter(displayId); + return; + } + final ComponentName targetComponentName = ComponentName.unflattenFromString(targetName); + if (targetComponentName == null) { + Slog.d(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName); + return; + } + // In case user assigned an accessibility framework feature to the given shortcut. + if (performAccessibilityFrameworkFeature(targetComponentName)) { + return; + } + // In case user assigned an accessibility shortcut target to the given shortcut. + if (performAccessibilityShortcutTargetActivity(displayId, targetComponentName)) { + return; + } + // in case user assigned an accessibility service to the given shortcut. + if (performAccessibilityShortcutTargetService( + displayId, shortcutType, targetComponentName)) { + return; + } + } + + private boolean performAccessibilityFrameworkFeature(ComponentName assignedTarget) { final Map<ComponentName, ToggleableFrameworkFeatureInfo> frameworkFeatureMap = AccessibilityShortcutController.getFrameworkShortcutFeaturesMap(); - synchronized(mLock) { - final AccessibilityUserState userState = getUserStateLocked(mCurrentUserId); - final ComponentName serviceName = userState.getServiceToEnableWithShortcutLocked(); - if (serviceName == null) { - return; - } - if (frameworkFeatureMap.containsKey(serviceName)) { - // Toggle the requested framework feature - ToggleableFrameworkFeatureInfo featureInfo = frameworkFeatureMap.get(serviceName); - SettingStringHelper setting = new SettingStringHelper(mContext.getContentResolver(), - featureInfo.getSettingKey(), mCurrentUserId); - // Assuming that the default state will be to have the feature off - if (!TextUtils.equals(featureInfo.getSettingOnValue(), setting.read())) { - setting.write(featureInfo.getSettingOnValue()); - } else { - setting.write(featureInfo.getSettingOffValue()); + if (!frameworkFeatureMap.containsKey(assignedTarget)) { + return false; + } + // Toggle the requested framework feature + final ToggleableFrameworkFeatureInfo featureInfo = frameworkFeatureMap.get(assignedTarget); + final SettingStringHelper setting = new SettingStringHelper(mContext.getContentResolver(), + featureInfo.getSettingKey(), mCurrentUserId); + // Assuming that the default state will be to have the feature off + if (!TextUtils.equals(featureInfo.getSettingOnValue(), setting.read())) { + setting.write(featureInfo.getSettingOnValue()); + } else { + setting.write(featureInfo.getSettingOffValue()); + } + return true; + } + + private boolean performAccessibilityShortcutTargetActivity(int displayId, + ComponentName assignedTarget) { + synchronized (mLock) { + final AccessibilityUserState userState = getCurrentUserStateLocked(); + for (int i = 0; i < userState.mInstalledShortcuts.size(); i++) { + final AccessibilityShortcutInfo shortcutInfo = userState.mInstalledShortcuts.get(i); + if (!shortcutInfo.getComponentName().equals(assignedTarget)) { + continue; } + launchShortcutTargetActivity(displayId, assignedTarget); + return true; } - final long identity = Binder.clearCallingIdentity(); - try { - if (userState.mComponentNameToServiceMap.get(serviceName) == null) { - enableAccessibilityServiceLocked(serviceName, mCurrentUserId); + } + return false; + } + + /** + * Perform accessibility service shortcut action. + * + * 1) For {@link AccessibilityManager#ACCESSIBILITY_BUTTON} type and services targeting sdk + * version <= Q: callbacks to accessibility service if service is bounded and requests + * accessibility button. + * 2) For {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY} type and service targeting sdk + * version <= Q: turns on / off the accessibility service. + * 3) For services targeting sdk version > Q: + * a) Turns on / off the accessibility service, if service does not request accessibility + * button. + * b) Callbacks to accessibility service if service is bounded and requests accessibility + * button. + */ + private boolean performAccessibilityShortcutTargetService(int displayId, + @ShortcutType int shortcutType, ComponentName assignedTarget) { + synchronized (mLock) { + final AccessibilityUserState userState = getCurrentUserStateLocked(); + final AccessibilityServiceInfo installedServiceInfo = + userState.getInstalledServiceInfoLocked(assignedTarget); + if (installedServiceInfo == null) { + Slog.d(LOG_TAG, "Perform shortcut failed, invalid component name:" + + assignedTarget); + return false; + } + + final AccessibilityServiceConnection serviceConnection = + userState.getServiceConnectionLocked(assignedTarget); + final int targetSdk = installedServiceInfo.getResolveInfo() + .serviceInfo.applicationInfo.targetSdkVersion; + final boolean requestA11yButton = (installedServiceInfo.flags + & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; + // Turns on / off the accessibility service + if ((targetSdk <= Build.VERSION_CODES.Q && shortcutType == ACCESSIBILITY_SHORTCUT_KEY) + || (targetSdk > Build.VERSION_CODES.Q && !requestA11yButton)) { + if (serviceConnection == null) { + enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId); } else { - disableAccessibilityServiceLocked(serviceName, mCurrentUserId); + disableAccessibilityServiceLocked(assignedTarget, mCurrentUserId); } - } finally { - Binder.restoreCallingIdentity(identity); + return true; + } + // Callbacks to a11y service if it's bounded and requests a11y button. + if (serviceConnection == null + || !userState.mBoundServices.contains(serviceConnection) + || !serviceConnection.mRequestAccessibilityButton) { + Slog.d(LOG_TAG, "Perform shortcut failed, service is not ready:" + + assignedTarget); + return false; } + serviceConnection.notifyAccessibilityButtonClickedLocked(displayId); + return true; } - }; + } @Override - public String getAccessibilityShortcutService() { - if (mContext.checkCallingPermission(Manifest.permission.MANAGE_ACCESSIBILITY) + public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) { + if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException( "getAccessibilityShortcutService requires the MANAGE_ACCESSIBILITY permission"); } - synchronized(mLock) { - final AccessibilityUserState userState = getUserStateLocked(mCurrentUserId); - if (userState.getServiceToEnableWithShortcutLocked() == null) { - return null; + return getAccessibilityShortcutTargetsInternal(shortcutType); + } + + private List<String> getAccessibilityShortcutTargetsInternal(@ShortcutType int shortcutType) { + synchronized (mLock) { + final AccessibilityUserState userState = getCurrentUserStateLocked(); + final ArrayList<String> shortcutTargets = new ArrayList<>( + userState.getShortcutTargetsLocked(shortcutType)); + if (shortcutType != ACCESSIBILITY_BUTTON) { + return shortcutTargets; + } + // Adds legacy a11y services requesting a11y button into the list. + for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { + final AccessibilityServiceConnection service = userState.mBoundServices.get(i); + if (!service.mRequestAccessibilityButton + || service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo + .targetSdkVersion > Build.VERSION_CODES.Q) { + continue; + } + final String serviceName = service.getComponentName().flattenToString(); + if (!TextUtils.isEmpty(serviceName)) { + shortcutTargets.add(serviceName); + } } - return userState.getServiceToEnableWithShortcutLocked().flattenToString(); + return shortcutTargets; } } @@ -2609,6 +2793,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); + // TODO(a11y shortcut): Remove this setting key, and have a migrate function in + // Setting provider after new shortcut UI merged. private final Uri mNavBarMagnificationEnabledUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED); @@ -2713,7 +2899,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub || mShowImeWithHardKeyboardUri.equals(uri)) { userState.reconcileSoftKeyboardModeWithSettingsLocked(); } else if (mAccessibilityShortcutServiceIdUri.equals(uri)) { - if (readAccessibilityShortcutSettingLocked(userState)) { + if (readAccessibilityShortcutKeySettingLocked(userState)) { onUserStateChangedLocked(userState); } } else if (mAccessibilityButtonComponentIdUri.equals(uri)) { @@ -2724,8 +2910,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub || mUserInteractiveUiTimeoutUri.equals(uri)) { readUserRecommendedUiTimeoutSettingsLocked(userState); } - // TODO(a11y shortcut): Monitor new setting keys, when user adds shortcut, and - // remove from the list of enabled targets anything that's been uninstalled. } } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java index 6cadb6d0f31f..cbff6bdcec77 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java @@ -294,6 +294,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect } } + // TODO(a11y shortcut): Refactoring the logic here, after the new Settings shortcut Ui merged. public boolean isAccessibilityButtonAvailableLocked(AccessibilityUserState userState) { // If the service does not request the accessibility button, it isn't available if (!mRequestAccessibilityButton) { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java index a0b9866e24d2..a163f7434e1f 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java @@ -22,6 +22,11 @@ import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_K import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_MASK; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; +import static android.view.accessibility.AccessibilityManager.ShortcutType; + +import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import android.accessibilityservice.AccessibilityService.SoftKeyboardShowMode; import android.accessibilityservice.AccessibilityServiceInfo; @@ -33,10 +38,14 @@ import android.content.Context; import android.os.Binder; import android.os.RemoteCallbackList; import android.provider.Settings; +import android.text.TextUtils; +import android.util.ArraySet; import android.util.Slog; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IAccessibilityManagerClient; +import com.android.internal.accessibility.AccessibilityShortcutController; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; @@ -79,19 +88,18 @@ class AccessibilityUserState { final Set<ComponentName> mTouchExplorationGrantedServices = new HashSet<>(); - private final ServiceInfoChangeListener mServiceInfoChangeListener; + final ArraySet<String> mAccessibilityShortcutKeyTargets = new ArraySet<>(); - private ComponentName mServiceAssignedToAccessibilityButton; + final ArraySet<String> mAccessibilityButtonTargets = new ArraySet<>(); - private ComponentName mServiceChangingSoftKeyboardMode; + private final ServiceInfoChangeListener mServiceInfoChangeListener; - private ComponentName mServiceToEnableWithShortcut; + private ComponentName mServiceChangingSoftKeyboardMode; private boolean mBindInstantServiceAllowed; private boolean mIsAutoclickEnabled; private boolean mIsDisplayMagnificationEnabled; private boolean mIsFilterKeyEventsEnabled; - private boolean mIsNavBarMagnificationAssignedToAccessibilityButton; private boolean mIsNavBarMagnificationEnabled; private boolean mIsPerformGesturesEnabled; private boolean mIsTextHighContrastEnabled; @@ -141,11 +149,11 @@ class AccessibilityUserState { // Clear state persisted in settings. mEnabledServices.clear(); mTouchExplorationGrantedServices.clear(); + mAccessibilityShortcutKeyTargets.clear(); + mAccessibilityButtonTargets.clear(); mIsTouchExplorationEnabled = false; mIsDisplayMagnificationEnabled = false; mIsNavBarMagnificationEnabled = false; - mServiceAssignedToAccessibilityButton = null; - mIsNavBarMagnificationAssignedToAccessibilityButton = false; mIsAutoclickEnabled = false; mUserNonInteractiveUiTimeout = 0; mUserInteractiveUiTimeout = 0; @@ -435,6 +443,26 @@ class AccessibilityUserState { pw.append(", installedServiceCount=").append(String.valueOf(mInstalledServices.size())); pw.append("}"); pw.println(); + pw.append(" shortcut key:{"); + int size = mAccessibilityShortcutKeyTargets.size(); + for (int i = 0; i < size; i++) { + final String componentId = mAccessibilityShortcutKeyTargets.valueAt(i); + pw.append(componentId); + if (i + 1 < size) { + pw.append(", "); + } + } + pw.println("}"); + pw.append(" button:{"); + size = mAccessibilityButtonTargets.size(); + for (int i = 0; i < size; i++) { + final String componentId = mAccessibilityButtonTargets.valueAt(i); + pw.append(componentId); + if (i + 1 < size) { + pw.append(", "); + } + } + pw.println("}"); pw.append(" Bound services:{"); final int serviceCount = mBoundServices.size(); for (int j = 0; j < serviceCount; j++) { @@ -525,20 +553,85 @@ class AccessibilityUserState { mLastSentClientState = state; } - public boolean isNavBarMagnificationAssignedToAccessibilityButtonLocked() { - return mIsNavBarMagnificationAssignedToAccessibilityButton; + public boolean isShortcutKeyMagnificationEnabledLocked() { + return mAccessibilityShortcutKeyTargets.contains(MAGNIFICATION_CONTROLLER_NAME); } - public void setNavBarMagnificationAssignedToAccessibilityButtonLocked(boolean assigned) { - mIsNavBarMagnificationAssignedToAccessibilityButton = assigned; + /** + * Disable both shortcuts' magnification function. + */ + public void disableShortcutMagnificationLocked() { + mAccessibilityShortcutKeyTargets.remove(MAGNIFICATION_CONTROLLER_NAME); + mAccessibilityButtonTargets.remove(MAGNIFICATION_CONTROLLER_NAME); } - public boolean isNavBarMagnificationEnabledLocked() { - return mIsNavBarMagnificationEnabled; + /** + * Returns a set which contains the flattened component names and the system class names + * assigned to the given shortcut. + * + * @param shortcutType The shortcut type. + * @return The array set of the strings + */ + public ArraySet<String> getShortcutTargetsLocked(@ShortcutType int shortcutType) { + if (shortcutType == ACCESSIBILITY_SHORTCUT_KEY) { + return mAccessibilityShortcutKeyTargets; + } else if (shortcutType == ACCESSIBILITY_BUTTON) { + return mAccessibilityButtonTargets; + } + return null; } - public void setNavBarMagnificationEnabledLocked(boolean enabled) { - mIsNavBarMagnificationEnabled = enabled; + /** + * Whether or not the given shortcut target is installed in device. + * + * @param name The shortcut target name + * @return true if the shortcut target is installed. + */ + public boolean isShortcutTargetInstalledLocked(String name) { + if (TextUtils.isEmpty(name)) { + return false; + } + if (MAGNIFICATION_CONTROLLER_NAME.equals(name)) { + return true; + } + + final ComponentName componentName = ComponentName.unflattenFromString(name); + if (componentName == null) { + return false; + } + if (AccessibilityShortcutController.getFrameworkShortcutFeaturesMap() + .containsKey(componentName)) { + return true; + } + if (getInstalledServiceInfoLocked(componentName) != null) { + return true; + } + for (int i = 0; i < mInstalledShortcuts.size(); i++) { + if (mInstalledShortcuts.get(i).getComponentName().equals(componentName)) { + return true; + } + } + return false; + } + + /** + * Returns installed accessibility service info by the given service component name. + */ + public AccessibilityServiceInfo getInstalledServiceInfoLocked(ComponentName componentName) { + for (int i = 0; i < mInstalledServices.size(); i++) { + final AccessibilityServiceInfo serviceInfo = mInstalledServices.get(i); + if (serviceInfo.getComponentName().equals(componentName)) { + return serviceInfo; + } + } + return null; + } + + /** + * Returns accessibility service connection by the given service component name. + */ + public AccessibilityServiceConnection getServiceConnectionLocked(ComponentName componentName) { + return mComponentNameToServiceMap.get(componentName); } public int getNonInteractiveUiTimeoutLocked() { @@ -557,14 +650,6 @@ class AccessibilityUserState { mIsPerformGesturesEnabled = enabled; } - public ComponentName getServiceAssignedToAccessibilityButtonLocked() { - return mServiceAssignedToAccessibilityButton; - } - - public void setServiceAssignedToAccessibilityButtonLocked(ComponentName componentName) { - mServiceAssignedToAccessibilityButton = componentName; - } - public ComponentName getServiceChangingSoftKeyboardModeLocked() { return mServiceChangingSoftKeyboardMode; } @@ -574,14 +659,6 @@ class AccessibilityUserState { mServiceChangingSoftKeyboardMode = serviceChangingSoftKeyboardMode; } - public ComponentName getServiceToEnableWithShortcutLocked() { - return mServiceToEnableWithShortcut; - } - - public void setServiceToEnableWithShortcutLocked(ComponentName componentName) { - mServiceToEnableWithShortcut = componentName; - } - public boolean isTextHighContrastEnabledLocked() { return mIsTextHighContrastEnabled; } @@ -613,4 +690,28 @@ class AccessibilityUserState { public void setUserNonInteractiveUiTimeoutLocked(int timeout) { mUserNonInteractiveUiTimeout = timeout; } + + // TODO(a11y shortcut): These functions aren't necessary, after the new Settings shortcut Ui + // is merged. + boolean isNavBarMagnificationEnabledLocked() { + return mIsNavBarMagnificationEnabled; + } + + void setNavBarMagnificationEnabledLocked(boolean enabled) { + mIsNavBarMagnificationEnabled = enabled; + } + + boolean isNavBarMagnificationAssignedToAccessibilityButtonLocked() { + return mAccessibilityButtonTargets.contains(MAGNIFICATION_CONTROLLER_NAME); + } + + ComponentName getServiceAssignedToAccessibilityButtonLocked() { + final String targetName = mAccessibilityButtonTargets.isEmpty() ? null + : mAccessibilityButtonTargets.valueAt(0); + if (targetName == null) { + return null; + } + return ComponentName.unflattenFromString(targetName); + } + // TODO(a11y shortcut): End } diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index be597d7b40d6..de6a080f1330 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -766,8 +766,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { backupManagerService.prepareOperationTimeout( mEphemeralOpToken, restoreAgentTimeoutMillis, this, OP_TYPE_RESTORE_WAIT); startedAgentRestore = true; - mAgent.doRestore(mBackupData, appVersionCode, mNewState, - mEphemeralOpToken, backupManagerService.getBackupManagerBinder()); + mAgent.doRestoreWithExcludedKeys(mBackupData, appVersionCode, mNewState, + mEphemeralOpToken, backupManagerService.getBackupManagerBinder(), + mExcludedKeys.containsKey(packageName) + ? new ArrayList<>(mExcludedKeys.get(packageName)) : null); } catch (Exception e) { Slog.e(TAG, "Unable to call app for restore: " + packageName, e); EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index de6cca520e65..53f306bae8e5 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -29,6 +29,8 @@ import android.content.pm.PackageManager.ApplicationInfoFlags; import android.content.pm.PackageManager.ComponentInfoFlags; import android.content.pm.PackageManager.PackageInfoFlags; import android.content.pm.PackageManager.ResolveInfoFlags; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils; import android.os.Bundle; import android.os.PersistableBundle; import android.util.ArraySet; @@ -326,7 +328,7 @@ public abstract class PackageManagerInternal { * @param installed the new installed state * @return true if the installed state changed as a result */ - public abstract boolean setInstalled(PackageParser.Package pkg, + public abstract boolean setInstalled(AndroidPackage pkg, @UserIdInt int userId, boolean installed); /** @@ -405,7 +407,7 @@ public abstract class PackageManagerInternal { * Returns whether or not the given package represents a legacy system application released * prior to runtime permissions. */ - public abstract boolean isLegacySystemApp(PackageParser.Package pkg); + public abstract boolean isLegacySystemApp(AndroidPackage pkg); /** * Get all overlay packages for a user. @@ -497,13 +499,17 @@ public abstract class PackageManagerInternal { /** * Returns a package object for the given package name. */ - public abstract @Nullable PackageParser.Package getPackage(@NonNull String packageName); + public abstract @Nullable AndroidPackage getPackage(@NonNull String packageName); + + // TODO(b/135203078): PackageSetting can't be referenced directly. Should move to a server side + // internal PM which is aware of PS. + public abstract @Nullable Object getPackageSetting(String packageName); /** * Returns a package for the given UID. If the UID is part of a shared user ID, one * of the packages will be chosen to be returned. */ - public abstract @Nullable PackageParser.Package getPackage(int uid); + public abstract @Nullable AndroidPackage getPackage(int uid); /** * Returns a list without a change observer. @@ -534,17 +540,19 @@ public abstract class PackageManagerInternal { */ public abstract void removePackageListObserver(@NonNull PackageListObserver observer); + // TODO(b/135203078): PackageSetting can't be referenced directly /** * Returns a package object for the disabled system package name. */ - public abstract @Nullable PackageParser.Package getDisabledSystemPackage( - @NonNull String packageName); + public abstract @Nullable Object getDisabledSystemPackage(@NonNull String packageName); /** * Returns the package name for the disabled system package. * * This is equivalent to - * {@link #getDisabledSystemPackage(String)}.{@link PackageParser.Package#packageName} + * {@link #getDisabledSystemPackage(String)} + * .{@link com.android.server.pm.PackageSetting#pkg} + * .{@link AndroidPackage#getPackageName()} */ public abstract @Nullable String getDisabledSystemPackageName(@NonNull String packageName); @@ -579,7 +587,7 @@ public abstract class PackageManagerInternal { * @see #canAccessInstantApps */ public abstract boolean filterAppAccess( - @NonNull PackageParser.Package pkg, int callingUid, int userId); + @NonNull AndroidPackage pkg, int callingUid, int userId); /** * Returns whether or not access to the application should be filtered. @@ -653,7 +661,8 @@ public abstract class PackageManagerInternal { throws IOException; /** Returns {@code true} if the specified component is enabled and matches the given flags. */ - public abstract boolean isEnabledAndMatches(@NonNull ComponentInfo info, int flags, int userId); + public abstract boolean isEnabledAndMatches( + @NonNull ComponentParseUtils.ParsedComponent component, int flags, int userId); /** Returns {@code true} if the given user requires extra badging for icons. */ public abstract boolean userNeedsBadging(int userId); @@ -664,14 +673,14 @@ public abstract class PackageManagerInternal { * * @param actionLocked action to be performed */ - public abstract void forEachPackage(Consumer<PackageParser.Package> actionLocked); + public abstract void forEachPackage(Consumer<AndroidPackage> actionLocked); /** * Perform the given action for each installed package for a user. * Note that packages lock will be held while performin the actions. */ public abstract void forEachInstalledPackage( - @NonNull Consumer<PackageParser.Package> actionLocked, @UserIdInt int userId); + @NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId); /** Returns the list of enabled components */ public abstract ArraySet<String> getEnabledComponents(String packageName, int userId); @@ -806,11 +815,26 @@ public abstract class PackageManagerInternal { * Otherwise, {@code false}. */ public abstract boolean isCallerInstallerOfRecord( - @NonNull PackageParser.Package pkg, int callingUid); + @NonNull AndroidPackage pkg, int callingUid); /** Returns whether or not default runtime permissions are granted for the given user */ public abstract boolean areDefaultRuntimePermissionsGranted(@UserIdInt int userId); /** Sets the enforcement of reading external storage */ public abstract void setReadExternalStorageEnforced(boolean enforced); + + /** + * Allows the integrity component to respond to the + * {@link Intent#ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION package verification + * broadcast} to respond to the package manager. The response must include + * the {@code verificationCode} which is one of + * {@link PackageManager#VERIFICATION_ALLOW} or + * {@link PackageManager#VERIFICATION_REJECT}. + * + * @param verificationId pending package identifier as passed via the + * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra. + * @param verificationResult either {@link PackageManager#VERIFICATION_ALLOW} + * or {@link PackageManager#VERIFICATION_REJECT}. + */ + public abstract void setIntegrityVerificationResult(int verificationId, int verificationResult); } diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index a3188443591f..119b987f7ae7 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -614,22 +614,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } public boolean isEnabled() { - if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { - Slog.w(TAG, "isEnabled(): not allowed for non-active and non system user"); - return false; - } - - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - return mBluetooth.isEnabled(); - } - } catch (RemoteException e) { - Slog.e(TAG, "isEnabled()", e); - } finally { - mBluetoothLock.readLock().unlock(); - } - return false; + return getState() == BluetoothAdapter.STATE_ON; } public int getState() { @@ -1796,14 +1781,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { //Do enable request try { - if (!mQuietEnable) { - if (!mBluetooth.enable()) { - Slog.e(TAG, "IBluetooth.enable() returned false"); - } - } else { - if (!mBluetooth.enableNoAutoConnect()) { - Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false"); - } + if (!mBluetooth.enable(mQuietEnable)) { + Slog.e(TAG, "IBluetooth.enable() returned false"); } } catch (RemoteException e) { Slog.e(TAG, "Unable to call enable()", e); @@ -2078,14 +2057,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } else if (mBluetooth != null) { //Enable bluetooth try { - if (!mQuietEnable) { - if (!mBluetooth.enable()) { - Slog.e(TAG, "IBluetooth.enable() returned false"); - } - } else { - if (!mBluetooth.enableNoAutoConnect()) { - Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false"); - } + if (!mBluetooth.enable(mQuietEnable)) { + Slog.e(TAG, "IBluetooth.enable() returned false"); } } catch (RemoteException e) { Slog.e(TAG, "Unable to call enable()", e); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 753c1171aeb3..f8f685d939a7 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5596,7 +5596,7 @@ public class ConnectivityService extends IConnectivityManager.Stub ns, mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mDnsResolver, mNMS, factorySerialNumber); // Make sure the network capabilities reflect what the agent info says. - nai.setNetworkCapabilities(mixInCapabilities(nai, nc)); + nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc)); final String extraInfo = networkInfo.getExtraInfo(); final String name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo; @@ -5950,11 +5950,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - final NetworkCapabilities prevNc; - synchronized (nai) { - prevNc = nai.networkCapabilities; - nai.setNetworkCapabilities(newNc); - } + final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc); updateUids(nai, prevNc, newNc); @@ -5963,7 +5959,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // the change we're processing can't affect any requests, it can only affect the listens // on this network. We might have been called by rematchNetworkAndRequests when a // network changed foreground state. - processListenRequests(nai, true); + processListenRequests(nai); } else { // If the requestable capabilities have changed or the score changed, we can't have been // called by rematchNetworkAndRequests, so it's safe to start a rematch. @@ -6271,8 +6267,14 @@ public class ConnectivityService extends IConnectivityManager.Stub updateAllVpnsCapabilities(); } - private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) { + private void processListenRequests(@NonNull final NetworkAgentInfo nai) { // For consistency with previous behaviour, send onLost callbacks before onAvailable. + processNewlyLostListenRequests(nai); + notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED); + processNewlySatisfiedListenRequests(nai); + } + + private void processNewlyLostListenRequests(@NonNull final NetworkAgentInfo nai) { for (NetworkRequestInfo nri : mNetworkRequests.values()) { NetworkRequest nr = nri.request; if (!nr.isListen()) continue; @@ -6281,11 +6283,9 @@ public class ConnectivityService extends IConnectivityManager.Stub callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0); } } + } - if (capabilitiesChanged) { - notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED); - } - + private void processNewlySatisfiedListenRequests(@NonNull final NetworkAgentInfo nai) { for (NetworkRequestInfo nri : mNetworkRequests.values()) { NetworkRequest nr = nri.request; if (!nr.isListen()) continue; @@ -6468,19 +6468,20 @@ public class ConnectivityService extends IConnectivityManager.Stub // before LegacyTypeTracker sends legacy broadcasts for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri); - // Second pass: process all listens. - if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) { - // TODO : most of the following is useless because the only thing that changed - // here is whether the network is a background network. Clean this up. + // Finally, process listen requests and update capabilities if the background state has + // changed for this network. For consistency with previous behavior, send onLost callbacks + // before onAvailable. + processNewlyLostListenRequests(newNetwork); - NetworkCapabilities newNc = mixInCapabilities(newNetwork, + // Maybe the network changed background states. Update its capabilities. + final boolean backgroundChanged = wasBackgroundNetwork != newNetwork.isBackgroundNetwork(); + if (backgroundChanged) { + final NetworkCapabilities newNc = mixInCapabilities(newNetwork, newNetwork.networkCapabilities); - if (Objects.equals(newNetwork.networkCapabilities, newNc)) return; - final int oldPermission = getNetworkPermission(newNetwork.networkCapabilities); final int newPermission = getNetworkPermission(newNc); - if (oldPermission != newPermission && newNetwork.created && !newNetwork.isVPN()) { + if (oldPermission != newPermission) { try { mNMS.setNetworkPermission(newNetwork.network.netId, newPermission); } catch (RemoteException e) { @@ -6488,53 +6489,11 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - final NetworkCapabilities prevNc; - synchronized (newNetwork) { - prevNc = newNetwork.networkCapabilities; - newNetwork.setNetworkCapabilities(newNc); - } - - updateUids(newNetwork, prevNc, newNc); - - if (newNetwork.getCurrentScore() == score - && newNc.equalRequestableCapabilities(prevNc)) { - // If the requestable capabilities haven't changed, and the score hasn't changed, - // then the change we're processing can't affect any requests, it can only affect - // the listens on this network. - processListenRequests(newNetwork, true); - } else { - rematchAllNetworksAndRequests(); - notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_CAP_CHANGED); - } - - if (prevNc != null) { - final boolean oldMetered = prevNc.isMetered(); - final boolean newMetered = newNc.isMetered(); - final boolean meteredChanged = oldMetered != newMetered; - - if (meteredChanged) { - maybeNotifyNetworkBlocked(newNetwork, oldMetered, newMetered, - mRestrictBackground, mRestrictBackground); - } - - final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) - != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING); - - // Report changes that are interesting for network statistics tracking. - if (meteredChanged || roamingChanged) { - notifyIfacesChangedForNetworkStats(); - } - } - - if (!newNc.hasTransport(TRANSPORT_VPN)) { - // Tell VPNs about updated capabilities, since they may need to - // bubble those changes through. - updateAllVpnsCapabilities(); - } - - } else { - processListenRequests(newNetwork, false); + newNetwork.getAndSetNetworkCapabilities(newNc); + notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_CAP_CHANGED); } + + processNewlySatisfiedListenRequests(newNetwork); } /** @@ -6719,9 +6678,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // NetworkCapabilities need to be set before sending the private DNS config to // NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required. - synchronized (networkAgent) { - networkAgent.setNetworkCapabilities(networkAgent.networkCapabilities); - } + networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities); + handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig()); updateLinkProperties(networkAgent, new LinkProperties(networkAgent.linkProperties), null); diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index f3089c1092e6..54dfc98e888d 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -81,6 +81,7 @@ import android.text.TextUtils; import android.util.EventLog; import android.util.Log; import android.util.Slog; +import android.util.SparseArray; import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; @@ -339,7 +340,7 @@ public class LocationManagerService extends ILocationManager.Stub { mSettingsStore.addOnLocationEnabledChangedListener((userId) -> { synchronized (mLock) { - onLocationModeChangedLocked(userId, true); + onLocationModeChangedLocked(userId); } }); mSettingsStore.addOnLocationProvidersAllowedChangedListener((userId) -> { @@ -467,36 +468,24 @@ public class LocationManagerService extends ILocationManager.Stub { } @GuardedBy("mLock") - private void onLocationModeChangedLocked(int userId, boolean broadcast) { - if (!isCurrentProfileLocked(userId)) { - return; - } - + private void onLocationModeChangedLocked(int userId) { if (D) { - Log.d(TAG, "location enabled is now " + isLocationEnabled()); + Log.d(TAG, "[u" + userId + "] location enabled = " + isLocationEnabledForUser(userId)); } - for (LocationProvider p : mProviders) { - p.onLocationModeChangedLocked(); - } + Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION); + intent.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabled()); + mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); - if (broadcast) { - // needs to be sent to everyone because we don't know which user may have changed - // LOCATION_MODE state. - mContext.sendBroadcastAsUser( - new Intent(LocationManager.MODE_CHANGED_ACTION), - UserHandle.ALL); + for (LocationProvider p : mProviders) { + p.onLocationModeChangedLocked(userId); } } @GuardedBy("mLock") private void onProviderAllowedChangedLocked(int userId) { - if (!isCurrentProfileLocked(userId)) { - return; - } - for (LocationProvider p : mProviders) { - p.onAllowedChangedLocked(); + p.onAllowedChangedLocked(userId); } } @@ -798,21 +787,14 @@ public class LocationManagerService extends ILocationManager.Stub { Log.d(TAG, "foreground user is changing to " + userId); } - // let providers know the current user is on the way out before changing the user - for (LocationProvider p : mProviders) { - p.onUserChangingLocked(); - } - + int oldUserId = userId; mCurrentUserId = userId; onUserProfilesChangedLocked(); - // if the user changes, per-user settings may also have changed - onLocationModeChangedLocked(userId, false); - onProviderAllowedChangedLocked(userId); - - // always force useability to be rechecked, even if no per-user settings have changed + // let providers know the current user has changed for (LocationProvider p : mProviders) { - p.onUseableChangedLocked(false); + p.onCurrentUserChangedLocked(oldUserId); + p.onCurrentUserChangedLocked(mCurrentUserId); } } @@ -832,7 +814,7 @@ public class LocationManagerService extends ILocationManager.Stub { protected AbstractLocationProvider mProvider; @GuardedBy("mLock") - private boolean mUseable; // combined state + private SparseArray<Boolean> mUseable; // combined state for each user id @GuardedBy("mLock") private boolean mAllowed; // state of LOCATION_PROVIDERS_ALLOWED @GuardedBy("mLock") @@ -851,7 +833,7 @@ public class LocationManagerService extends ILocationManager.Stub { mIsManagedBySettings = isManagedBySettings; mProvider = null; - mUseable = false; + mUseable = new SparseArray<>(1); mAllowed = !mIsManagedBySettings; mEnabled = false; mProperties = null; @@ -876,7 +858,10 @@ public class LocationManagerService extends ILocationManager.Stub { } mProvider = provider; - onUseableChangedLocked(false); + + // it would be more correct to call this for all users, but we know this can only + // affect the current user since providers are disabled for non-current users + onUseableChangedLocked(false, mCurrentUserId); } public String getName() { @@ -943,8 +928,8 @@ public class LocationManagerService extends ILocationManager.Stub { pw.increaseIndent(); - pw.println("useable=" + mUseable); - if (!mUseable) { + pw.println("useable=" + isUseableLocked(mCurrentUserId)); + if (!isUseableLocked(mCurrentUserId)) { pw.println("attached=" + (mProvider != null)); if (mIsManagedBySettings) { pw.println("allowed=" + mAllowed); @@ -1009,7 +994,10 @@ public class LocationManagerService extends ILocationManager.Stub { } mEnabled = enabled; - onUseableChangedLocked(false); + + // it would be more correct to call this for all users, but we know this can only + // affect the current user since providers are disabled for non-current users + onUseableChangedLocked(false, mCurrentUserId); } } @@ -1021,12 +1009,20 @@ public class LocationManagerService extends ILocationManager.Stub { } @GuardedBy("mLock") - public void onLocationModeChangedLocked() { - onUseableChangedLocked(false); + public void onLocationModeChangedLocked(int userId) { + if (!isCurrentProfileLocked(userId)) { + return; + } + + onUseableChangedLocked(false, userId); } @GuardedBy("mLock") - public void onAllowedChangedLocked() { + public void onAllowedChangedLocked(int userId) { + if (!isCurrentProfileLocked(userId)) { + return; + } + if (mIsManagedBySettings) { boolean allowed = mSettingsStore.getLocationProvidersAllowed( mCurrentUserId).contains(mName); @@ -1040,37 +1036,36 @@ public class LocationManagerService extends ILocationManager.Stub { } mAllowed = allowed; - onUseableChangedLocked(true); + onUseableChangedLocked(true, userId); } } @GuardedBy("mLock") - public boolean isUseableLocked() { - return isUseableForUserLocked(mCurrentUserId); + public void onCurrentUserChangedLocked(int userId) { + onUseableChangedLocked(false, userId); } @GuardedBy("mLock") - public boolean isUseableForUserLocked(int userId) { - return isCurrentProfileLocked(userId) && mUseable; + public boolean isUseableLocked() { + return isUseableLocked(mCurrentUserId); } @GuardedBy("mLock") - private boolean isUseableIgnoringAllowedLocked() { - return mProvider != null && mProviders.contains(this) && isLocationEnabled() - && mEnabled; + public boolean isUseableLocked(int userId) { + return mUseable.get(userId, Boolean.FALSE); } @GuardedBy("mLock") - public void onUseableChangedLocked(boolean isAllowedChanged) { + public void onUseableChangedLocked(boolean isAllowedChanged, int userId) { // if any property that contributes to "useability" here changes state, it MUST result // in a direct or indrect call to onUseableChangedLocked. this allows the provider to // guarantee that it will always eventually reach the correct state. - boolean useableIgnoringAllowed = isUseableIgnoringAllowedLocked(); + boolean useableIgnoringAllowed = mProvider != null && mProviders.contains(this) + && isCurrentProfileLocked(userId) && isLocationEnabledForUser(userId) + && mEnabled; boolean useable = useableIgnoringAllowed && mAllowed; - // update deprecated provider allowed settings for backwards compatibility, and do this - // even if there is no change in overall useability state. this may result in trying to - // overwrite the same value, but Settings handles deduping this. + // update deprecated provider allowed settings for backwards compatibility if (mIsManagedBySettings) { // a "-" change derived from the allowed setting should not be overwritten, but a // "+" change should be corrected if necessary @@ -1079,33 +1074,31 @@ public class LocationManagerService extends ILocationManager.Stub { mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+" + mName, - mCurrentUserId); + userId); } else if (!useableIgnoringAllowed) { Settings.Secure.putStringForUser( mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-" + mName, - mCurrentUserId); + userId); } - // needs to be sent to all users because whether or not a provider is enabled for - // a given user is complicated... we broadcast to everyone and let them figure it - // out via isProviderEnabled() Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION); intent.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + intent.putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, useable); + mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); } - if (useable == mUseable) { + if (useable == isUseableLocked(userId)) { return; } - mUseable = useable; + mUseable.put(userId, useable); if (D) { - Log.d(TAG, mName + " provider useable is now " + mUseable); + Log.d(TAG, "[u" + userId + "] " + mName + " provider useable = " + useable); } - if (!mUseable) { + if (!useable) { // If any provider has been disabled, clear all last locations for all // providers. This is to be on the safe side in case a provider has location // derived from this disabled provider. @@ -1115,15 +1108,6 @@ public class LocationManagerService extends ILocationManager.Stub { updateProviderUseableLocked(this); } - - @GuardedBy("mLock") - public void onUserChangingLocked() { - // when the user is about to change, we set this provider to un-useable, and notify all - // of the current user clients. when the user is finished changing, useability will be - // updated back via onLocationModeChanged() and onAllowedChanged(). - mUseable = false; - updateProviderUseableLocked(this); - } } private class MockLocationProvider extends LocationProvider { @@ -1557,14 +1541,20 @@ public class LocationManagerService extends ILocationManager.Stub { mProviders.add(provider); - provider.onAllowedChangedLocked(); // allowed state may change while provider was inactive - provider.onUseableChangedLocked(false); + // allowed state may change while provider was inactive + provider.onAllowedChangedLocked(mCurrentUserId); + + // it would be more correct to call this for all users, but we know this can only + // affect the current user since providers are disabled for non-current users + provider.onUseableChangedLocked(false, mCurrentUserId); } @GuardedBy("mLock") private void removeProviderLocked(LocationProvider provider) { if (mProviders.remove(provider)) { - provider.onUseableChangedLocked(false); + // it would be more correct to call this for all users, but we know this can only + // affect the current user since providers are disabled for non-current users + provider.onUseableChangedLocked(false, mCurrentUserId); } } @@ -2851,7 +2841,7 @@ public class LocationManagerService extends ILocationManager.Stub { synchronized (mLock) { LocationProvider provider = getLocationProviderLocked(providerName); - return provider != null && provider.isUseableForUserLocked(userId); + return provider != null && provider.isUseableLocked(userId); } } @@ -3246,6 +3236,7 @@ public class LocationManagerService extends ILocationManager.Stub { synchronized (mLock) { if (mGnssManagerService != null && args.length > 0 && args[0].equals("--gnssmetrics")) { mGnssManagerService.dump(fd, pw, args); + return; } ipw.println("Location Manager State:"); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index e79a2897d86a..0d496b6b427d 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -16,6 +16,7 @@ package com.android.server; +import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.OBSERVE_NETWORK_POLICY; import static android.Manifest.permission.SHUTDOWN; @@ -57,6 +58,7 @@ import android.net.NetworkStack; import android.net.NetworkStats; import android.net.NetworkUtils; import android.net.RouteInfo; +import android.net.TetherConfigParcel; import android.net.TetherStatsParcel; import android.net.UidRange; import android.net.UidRangeParcel; @@ -737,7 +739,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub { // @Override public String[] listInterfaces() { - NetworkStack.checkNetworkStackPermission(mContext); + // TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these + // APIs. + NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL); try { return mNetdService.interfaceGetList(); } catch (RemoteException | ServiceSpecificException e) { @@ -787,7 +791,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public InterfaceConfiguration getInterfaceConfig(String iface) { - NetworkStack.checkNetworkStackPermission(mContext); + // TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these + // APIs. + NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL); final InterfaceConfigurationParcel result; try { result = mNetdService.interfaceGetCfg(iface); @@ -805,7 +811,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) { - NetworkStack.checkNetworkStackPermission(mContext); + // TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these + // APIs. + NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL); LinkAddress linkAddr = cfg.getLinkAddress(); if (linkAddr == null || linkAddr.getAddress() == null) { throw new IllegalStateException("Null LinkAddress given"); @@ -1016,7 +1024,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub { NetworkStack.checkNetworkStackPermission(mContext); // an odd number of addrs will fail try { - mNetdService.tetherStartWithConfiguration(usingLegacyDnsProxy, dhcpRange); + final TetherConfigParcel config = new TetherConfigParcel(); + config.usingLegacyDnsProxy = usingLegacyDnsProxy; + config.dhcpRanges = dhcpRange; + mNetdService.tetherStartWithConfiguration(config); } catch (RemoteException | ServiceSpecificException e) { throw new IllegalStateException(e); } diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index 12debbff3e90..521b39305d9d 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -57,6 +57,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; @@ -81,6 +82,22 @@ public class PackageWatchdog { static final String PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED = "watchdog_explicit_health_check_enabled"; + public static final int FAILURE_REASON_UNKNOWN = 0; + public static final int FAILURE_REASON_NATIVE_CRASH = 1; + public static final int FAILURE_REASON_EXPLICIT_HEALTH_CHECK = 2; + public static final int FAILURE_REASON_APP_CRASH = 3; + public static final int FAILURE_REASON_APP_NOT_RESPONDING = 4; + + @IntDef(prefix = { "FAILURE_REASON_" }, value = { + FAILURE_REASON_UNKNOWN, + FAILURE_REASON_NATIVE_CRASH, + FAILURE_REASON_EXPLICIT_HEALTH_CHECK, + FAILURE_REASON_APP_CRASH, + FAILURE_REASON_APP_NOT_RESPONDING + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FailureReasons {} + // Duration to count package failures before it resets to 0 @VisibleForTesting static final int DEFAULT_TRIGGER_FAILURE_DURATION_MS = @@ -305,14 +322,15 @@ public class PackageWatchdog { } /** - * Called when a process fails either due to a crash or ANR. + * Called when a process fails due to a crash, ANR or explicit health check. * * <p>For each package contained in the process, one registered observer with the least user * impact will be notified for mitigation. * * <p>This method could be called frequently if there is a severe problem on the device. */ - public void onPackageFailure(List<VersionedPackage> packages) { + public void onPackageFailure(List<VersionedPackage> packages, + @FailureReasons int failureReason) { mLongTaskHandler.post(() -> { synchronized (mLock) { if (mAllObservers.isEmpty()) { @@ -343,7 +361,7 @@ public class PackageWatchdog { // Execute action with least user impact if (currentObserverToNotify != null) { - currentObserverToNotify.execute(versionedPackage); + currentObserverToNotify.execute(versionedPackage, failureReason); } } } @@ -414,7 +432,7 @@ public class PackageWatchdog { * * @return {@code true} if action was executed successfully, {@code false} otherwise */ - boolean execute(VersionedPackage versionedPackage); + boolean execute(VersionedPackage versionedPackage, @FailureReasons int failureReason); // TODO(b/120598832): Ensure uniqueness? /** @@ -659,7 +677,8 @@ public class PackageWatchdog { while (it.hasNext()) { VersionedPackage versionedPkg = it.next().mPackage; Slog.i(TAG, "Explicit health check failed for package " + versionedPkg); - registeredObserver.execute(versionedPkg); + registeredObserver.execute(versionedPkg, + PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK); } } } @@ -770,7 +789,7 @@ public class PackageWatchdog { final List<VersionedPackage> pkgList = Collections.singletonList(pkg); final long failureCount = getTriggerFailureCount(); for (int i = 0; i < failureCount; i++) { - onPackageFailure(pkgList); + onPackageFailure(pkgList, FAILURE_REASON_EXPLICIT_HEALTH_CHECK); } }); } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 822fc90cd78e..0a6473ab92d9 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.INSTALL_PACKAGES; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import static android.Manifest.permission.WRITE_MEDIA_STORAGE; +import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.OP_LEGACY_STORAGE; import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE; @@ -49,6 +50,7 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.Manifest; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.KeyguardManager; @@ -253,6 +255,11 @@ class StorageManagerService extends IStorageManager.Stub public void onCleanupUser(int userHandle) { mStorageManagerService.onCleanupUser(userHandle); } + + @Override + public void onStopUser(int userHandle) { + mStorageManagerService.onStopUser(userHandle); + } } private static final boolean DEBUG_EVENTS = false; @@ -1075,6 +1082,15 @@ class StorageManagerService extends IStorageManager.Stub } } + private void onStopUser(int userId) { + Slog.i(TAG, "onStopUser " + userId); + try { + mStorageSessionController.onUserStopping(userId); + } catch (Exception e) { + Slog.wtf(TAG, e); + } + } + private boolean supportsBlockCheckpoint() throws RemoteException { enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); return mVold.supportsBlockCheckpoint(); @@ -1309,6 +1325,15 @@ class StorageManagerService extends IStorageManager.Stub Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId()); return; } + final ActivityManagerInternal amInternal = + LocalServices.getService(ActivityManagerInternal.class); + + if (mIsFuseEnabled && vol.mountUserId >= 0 + && !amInternal.isUserRunning(vol.mountUserId, 0)) { + Slog.d(TAG, "Ignoring volume " + vol.getId() + " because user " + + Integer.toString(vol.mountUserId) + " is no longer running."); + return; + } if (vol.type == VolumeInfo.TYPE_EMULATED) { final StorageManager storage = mContext.getSystemService(StorageManager.class); @@ -2229,6 +2254,11 @@ class StorageManagerService extends IStorageManager.Stub } private void remountUidExternalStorage(int uid, int mode) { + if (uid == Process.SYSTEM_UID) { + // No need to remount uid for system because it has all access anyways + return; + } + try { mVold.remountUid(uid, mode); } catch (Exception e) { @@ -3399,7 +3429,13 @@ class StorageManagerService extends IStorageManager.Stub public void opChanged(int op, int uid, String packageName) throws RemoteException { if (!ENABLE_ISOLATED_STORAGE) return; - remountUidExternalStorage(uid, getMountMode(uid, packageName)); + int mountMode = getMountMode(uid, packageName); + boolean isUidActive = LocalServices.getService(ActivityManagerInternal.class) + .getUidProcessState(uid) != PROCESS_STATE_NONEXISTENT; + + if (isUidActive) { + remountUidExternalStorage(uid, mountMode); + } } }; @@ -4092,6 +4128,13 @@ class StorageManagerService extends IStorageManager.Stub } } + @Override + public void resetUser(int userId) { + // TODO(b/145931219): ideally, we only reset storage for the user in question, + // but for now, reset everything. + mHandler.obtainMessage(H_RESET).sendToTarget(); + } + public boolean hasExternalStorage(int uid, String packageName) { // No need to check for system uid. This avoids a deadlock between // PackageManagerService and AppOpsService. diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 1f7d9eab9675..f9b358ceada9 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -72,7 +72,6 @@ import com.android.internal.app.IBatteryStats; import com.android.internal.telephony.IOnSubscriptionsChangedListener; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.ITelephonyRegistry; -import com.android.internal.telephony.PhoneConstantConversions; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; @@ -358,7 +357,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.getDefaultSubscriptionId()); int newDefaultPhoneId = intent.getIntExtra( - PhoneConstants.PHONE_KEY, + SubscriptionManager.EXTRA_SLOT_INDEX, SubscriptionManager.getPhoneId(newDefaultSubId)); if (DBG) { log("onReceive:current mDefaultSubId=" + mDefaultSubId @@ -447,9 +446,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mOtaspMode[i] = TelephonyManager.OTASP_UNKNOWN; mCallDisconnectCause[i] = DisconnectCause.NOT_VALID; mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID; - mCallQuality[i] = new CallQuality(); + mCallQuality[i] = createCallQuality(); mCallAttributes[i] = new CallAttributes(new PreciseCallState(), - TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality()); + TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality()); mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN; mPreciseCallState[i] = new PreciseCallState(); mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE; @@ -542,9 +541,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mOtaspMode[i] = TelephonyManager.OTASP_UNKNOWN; mCallDisconnectCause[i] = DisconnectCause.NOT_VALID; mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID; - mCallQuality[i] = new CallQuality(); + mCallQuality[i] = createCallQuality(); mCallAttributes[i] = new CallAttributes(new PreciseCallState(), - TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality()); + TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality()); mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN; mPreciseCallState[i] = new PreciseCallState(); mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE; @@ -1705,7 +1704,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (mPreciseCallState[phoneId].getForegroundCallState() != PreciseCallState.PRECISE_CALL_STATE_ACTIVE) { mCallNetworkType[phoneId] = TelephonyManager.NETWORK_TYPE_UNKNOWN; - mCallQuality[phoneId] = new CallQuality(); + mCallQuality[phoneId] = createCallQuality(); } mCallAttributes[phoneId] = new CallAttributes(mPreciseCallState[phoneId], mCallNetworkType[phoneId], mCallQuality[phoneId]); @@ -1733,8 +1732,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } handleRemoveListLocked(); } - broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState, - backgroundCallState); } public void notifyDisconnectCause(int phoneId, int subId, int disconnectCause, @@ -2147,6 +2144,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // the legacy intent broadcasting // + // Legacy intent action. + /** Fired when a subscription's phone state changes. */ + private static final String ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED = + "android.intent.action.SUBSCRIPTION_PHONE_STATE"; + + // Legacy intent extra keys, copied from PhoneConstants. + // Used in legacy intents sent here, for backward compatibility. + private static final String PHONE_CONSTANTS_SLOT_KEY = "slot"; + private static final String PHONE_CONSTANTS_SUBSCRIPTION_KEY = "subscription"; + private void broadcastServiceStateChanged(ServiceState state, int phoneId, int subId) { long ident = Binder.clearCallingIdentity(); try { @@ -2163,9 +2170,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { state.fillInNotifierBundle(data); intent.putExtras(data); // Pass the subscription along with the intent. - intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); + intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); - intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); + intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); + intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } @@ -2184,8 +2192,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { Bundle data = new Bundle(); signalStrength.fillInNotifierBundle(data); intent.putExtras(data); - intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); - intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); + intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); + intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } @@ -2215,19 +2223,19 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED); - intent.putExtra(PhoneConstants.STATE_KEY, - PhoneConstantConversions.convertCallState(state).toString()); + intent.putExtra(TelephonyManager.EXTRA_STATE, callStateToString(state)); // If a valid subId was specified, we should fire off a subId-specific state // change intent and include the subId. if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - intent.setAction(PhoneConstants.ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED); - intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); + intent.setAction(ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED); + intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); } // If the phoneId is invalid, the broadcast is for overall call state. if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) { - intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); + intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); + intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId); } // Wakeup apps for the (SUBSCRIPTION_)PHONE_STATE broadcast. @@ -2249,6 +2257,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { android.Manifest.permission.READ_CALL_LOG}); } + /** Converts TelephonyManager#CALL_STATE_* to TelephonyManager#EXTRA_STATE_*. */ + private static String callStateToString(int callState) { + switch (callState) { + case TelephonyManager.CALL_STATE_RINGING: + return TelephonyManager.EXTRA_STATE_RINGING; + case TelephonyManager.CALL_STATE_OFFHOOK: + return TelephonyManager.EXTRA_STATE_OFFHOOK; + default: + return TelephonyManager.EXTRA_STATE_IDLE; + } + } + private void broadcastDataConnectionStateChanged(int state, boolean isDataAllowed, String apn, String apnType, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, @@ -2257,8 +2277,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // status bar takes care of that after taking into account all of the // required info. Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); - intent.putExtra(PhoneConstants.STATE_KEY, - PhoneConstantConversions.convertDataState(state).toString()); + intent.putExtra(TelephonyManager.EXTRA_STATE, dataStateToString(state)); if (!isDataAllowed) { intent.putExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY, true); } @@ -2276,32 +2295,22 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { intent.putExtra(PhoneConstants.DATA_APN_KEY, apn); intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType); - intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); + intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } private void broadcastDataConnectionFailed(String apnType, int subId) { Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType); - intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); + intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } - private void broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState, - int backgroundCallState) { - Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED); - intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState); - intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState); - intent.putExtra(TelephonyManager.EXTRA_BACKGROUND_CALL_STATE, backgroundCallState); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL, - android.Manifest.permission.READ_PRECISE_PHONE_STATE); - } - private void broadcastPreciseDataConnectionStateChanged(int state, int networkType, String apnType, String apn, LinkProperties linkProperties, @DataFailureCause int failCause) { Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED); - intent.putExtra(PhoneConstants.STATE_KEY, state); + intent.putExtra(TelephonyManager.EXTRA_STATE, state); intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType); if (apnType != null) intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType); if (apn != null) intent.putExtra(PhoneConstants.DATA_APN_KEY, apn); @@ -2642,11 +2651,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } /** - * Convert data state to string + * Convert TelephonyManager.DATA_* to string. * * @return The data state in string format. */ - private String dataStateToString(@TelephonyManager.DataState int state) { + private static String dataStateToString(int state) { switch (state) { case TelephonyManager.DATA_DISCONNECTED: return "DISCONNECTED"; case TelephonyManager.DATA_CONNECTING: return "CONNECTING"; @@ -2710,4 +2719,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + /** Returns a new CallQuality object with default values. */ + private static CallQuality createCallQuality() { + return new CallQuality(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } } diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index b5702541432a..a4a6f23fc894 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -56,6 +56,7 @@ import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; import android.util.ArraySet; import android.util.Slog; + import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.DisableCarModeActivity; @@ -73,7 +74,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; -import static android.content.Intent.ACTION_SCREEN_OFF; final class UiModeManagerService extends SystemService { private static final String TAG = UiModeManager.class.getSimpleName(); @@ -97,6 +97,10 @@ final class UiModeManagerService extends SystemService { private boolean mCarModeEnabled = false; private boolean mCharging = false; private boolean mPowerSave = false; + // Do not change configuration now. wait until screen turns off. + // This prevents jank and activity restart when the user + // is actively using the device + private boolean mWaitForScreenOff = false; private int mDefaultUiModeType; private boolean mCarModeKeepsScreenOn; private boolean mDeskModeKeepsScreenOn; @@ -208,24 +212,23 @@ final class UiModeManagerService extends SystemService { public void onTwilightStateChanged(@Nullable TwilightState state) { synchronized (mLock) { if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { - final IntentFilter intentFilter = - new IntentFilter(ACTION_SCREEN_OFF); - getContext().registerReceiver(mOnScreenOffHandler, intentFilter); + registerScreenOffEvent(); } } } }; + /** + * DO NOT USE DIRECTLY + * see register registerScreenOffEvent and unregisterScreenOffEvent + */ private final BroadcastReceiver mOnScreenOffHandler = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { synchronized (mLock) { + // must unregister first before updating + unregisterScreenOffEvent(); updateLocked(0, 0); - try { - getContext().unregisterReceiver(mOnScreenOffHandler); - } catch (IllegalArgumentException e) { - // we ignore this exception if the receiver is unregistered already. - } } } }; @@ -335,7 +338,7 @@ final class UiModeManagerService extends SystemService { SystemServerInitThreadPool.submit(() -> { synchronized (mLock) { updateConfigurationLocked(); - sendConfigurationLocked(); + applyConfigurationExternallyLocked(); } }, TAG + ".onStart"); @@ -404,6 +407,22 @@ final class UiModeManagerService extends SystemService { return oldNightMode != mNightMode; } + private void registerScreenOffEvent() { + mWaitForScreenOff = true; + final IntentFilter intentFilter = + new IntentFilter(Intent.ACTION_SCREEN_OFF); + getContext().registerReceiver(mOnScreenOffHandler, intentFilter); + } + + private void unregisterScreenOffEvent() { + mWaitForScreenOff = false; + try { + getContext().unregisterReceiver(mOnScreenOffHandler); + } catch (IllegalArgumentException e) { + // we ignore this exception if the receiver is unregistered already. + } + } + private final IUiModeManager.Stub mService = new IUiModeManager.Stub() { @Override public void enableCarMode(@UiModeManager.EnableCarMode int flags, @@ -525,11 +544,7 @@ final class UiModeManagerService extends SystemService { synchronized (mLock) { if (mNightMode != mode) { if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { - try { - getContext().unregisterReceiver(mOnScreenOffHandler); - } catch (IllegalArgumentException e) { - // we ignore this exception if the receiver is unregistered already. - } + unregisterScreenOffEvent(); } // Only persist setting if not in car mode if (!mCarModeEnabled) { @@ -541,12 +556,11 @@ final class UiModeManagerService extends SystemService { mNightMode = mode; mNightModeOverride = mode; - //on screen off will update configuration instead + // on screen off will update configuration instead if (mNightMode != UiModeManager.MODE_NIGHT_AUTO) { updateLocked(0, 0); } else { - getContext().registerReceiver( - mOnScreenOffHandler, new IntentFilter(ACTION_SCREEN_OFF)); + registerScreenOffEvent(); } } } @@ -594,10 +608,7 @@ final class UiModeManagerService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { - try { - getContext().unregisterReceiver(mOnScreenOffHandler); - } catch (IllegalArgumentException e) { - } + unregisterScreenOffEvent(); mNightModeOverride = active ? UiModeManager.MODE_NIGHT_YES : UiModeManager.MODE_NIGHT_NO; } else if (mNightMode == UiModeManager.MODE_NIGHT_NO @@ -608,7 +619,7 @@ final class UiModeManagerService extends SystemService { mNightMode = UiModeManager.MODE_NIGHT_NO; } updateConfigurationLocked(); - sendConfigurationLocked(); + applyConfigurationExternallyLocked(); return true; } finally { Binder.restoreCallingIdentity(ident); @@ -863,17 +874,16 @@ final class UiModeManagerService extends SystemService { } mCurUiMode = uiMode; - if (!mHoldingConfiguration) { + if (!mHoldingConfiguration || !mWaitForScreenOff) { mConfiguration.uiMode = uiMode; } - // load splash screen instead of screenshot - mWindowManager.clearSnapshotCache(); } - private void sendConfigurationLocked() { + private void applyConfigurationExternallyLocked() { if (mSetUiMode != mConfiguration.uiMode) { mSetUiMode = mConfiguration.uiMode; - + // load splash screen instead of screenshot + mWindowManager.clearSnapshotCache(); try { ActivityTaskManager.getService().updateConfiguration(mConfiguration); } catch (RemoteException e) { @@ -1053,7 +1063,7 @@ final class UiModeManagerService extends SystemService { } // Send the new configuration. - sendConfigurationLocked(); + applyConfigurationExternallyLocked(); // If we did not start a dock app, then start dreaming if supported. if (category != null && !dockAppStarted) { @@ -1131,7 +1141,6 @@ final class UiModeManagerService extends SystemService { final int user = UserHandle.getCallingUserId(); Secure.putIntForUser(getContext().getContentResolver(), OVERRIDE_NIGHT_MODE, mNightModeOverride, user); - } } diff --git a/services/core/java/com/android/server/ZramWriteback.java b/services/core/java/com/android/server/ZramWriteback.java index 49bf29bff284..5d97def129a4 100644 --- a/services/core/java/com/android/server/ZramWriteback.java +++ b/services/core/java/com/android/server/ZramWriteback.java @@ -60,6 +60,7 @@ public final class ZramWriteback extends JobService { private static final String MARK_IDLE_DELAY_PROP = "ro.zram.mark_idle_delay_mins"; private static final String FIRST_WB_DELAY_PROP = "ro.zram.first_wb_delay_mins"; private static final String PERIODIC_WB_DELAY_PROP = "ro.zram.periodic_wb_delay_hours"; + private static final String FORCE_WRITEBACK_PROP = "zram.force_writeback"; private void markPagesAsIdle() { String idlePath = String.format(IDLE_SYS, sZramDeviceId); @@ -122,11 +123,12 @@ public final class ZramWriteback extends JobService { private static void schedNextWriteback(Context context) { int nextWbDelay = SystemProperties.getInt(PERIODIC_WB_DELAY_PROP, 24); + boolean forceWb = SystemProperties.getBoolean(FORCE_WRITEBACK_PROP, false); JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback) .setMinimumLatency(TimeUnit.HOURS.toMillis(nextWbDelay)) - .setRequiresDeviceIdle(true) + .setRequiresDeviceIdle(!forceWb) .build()); } @@ -167,6 +169,7 @@ public final class ZramWriteback extends JobService { public static void scheduleZramWriteback(Context context) { int markIdleDelay = SystemProperties.getInt(MARK_IDLE_DELAY_PROP, 20); int firstWbDelay = SystemProperties.getInt(FIRST_WB_DELAY_PROP, 180); + boolean forceWb = SystemProperties.getBoolean(FORCE_WRITEBACK_PROP, false); JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); @@ -182,7 +185,7 @@ public final class ZramWriteback extends JobService { // by ro.zram.periodic_wb_delay_hours. js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback) .setMinimumLatency(TimeUnit.MINUTES.toMillis(firstWbDelay)) - .setRequiresDeviceIdle(true) + .setRequiresDeviceIdle(!forceWb) .build()); } } diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index b5cab1f8d62b..e101fe0e192c 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -1289,6 +1289,33 @@ public class AccountManagerService } protected UserAccounts getUserAccounts(int userId) { + try { + return getUserAccountsNotChecked(userId); + } catch (RuntimeException e) { + if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { + // Let it go... + throw e; + } + // User accounts database is corrupted, we must wipe out the whole user, otherwise the + // system will crash indefinitely + Slog.wtf(TAG, "Removing user " + userId + " due to exception (" + e + ") reading its " + + "account database"); + if (userId == ActivityManager.getCurrentUser() && userId != UserHandle.USER_SYSTEM) { + Slog.i(TAG, "Switching to system user first"); + try { + ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM); + } catch (RemoteException re) { + Slog.e(TAG, "Could not switch to " + UserHandle.USER_SYSTEM + ": " + re); + } + } + if (!getUserManager().removeUserEvenWhenDisallowed(userId)) { + Slog.e(TAG, "could not remove user " + userId); + } + throw e; + } + } + + private UserAccounts getUserAccountsNotChecked(int userId) { synchronized (mUsers) { UserAccounts accounts = mUsers.get(userId); boolean validateAccounts = false; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b191338dc58c..01f3c2666ff7 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6694,7 +6694,7 @@ public class ActivityManagerService extends IActivityManager.Stub private final long[] mProcessStateStatsLongs = new long[1]; - private boolean isProcessAliveLocked(ProcessRecord proc) { + boolean isProcessAliveLocked(ProcessRecord proc) { if (proc.pid <= 0) { if (DEBUG_OOM_ADJ) Slog.d(TAG, "Process hasn't started yet: " + proc); return false; @@ -6711,7 +6711,10 @@ public class ActivityManagerService extends IActivityManager.Stub final long state = mProcessStateStatsLongs[0]; if (DEBUG_OOM_ADJ) Slog.d(TAG, "RETRIEVED STATE FOR " + proc.procStatFile + ": " + (char)state); - return state != 'Z' && state != 'X' && state != 'x' && state != 'K'; + if (state != 'Z' && state != 'X' && state != 'x' && state != 'K') { + return Process.getUidForPid(proc.pid) == proc.uid; + } + return false; } private String checkContentProviderAssociation(ProcessRecord callingApp, int callingUid, @@ -6784,14 +6787,14 @@ public class ActivityManagerService extends IActivityManager.Stub // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see // how to test this case.) if (cpr.proc.killed && cpr.proc.killedByAm) { - checkTime(startTime, "getContentProviderImpl: before appDied (killedByAm)"); final long iden = Binder.clearCallingIdentity(); try { - appDiedLocked(cpr.proc); + mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc, false, + cpr.uid == cpr.proc.uid || cpr.proc.isolated, + "getContentProviderImpl: %s (killedByAm)", startTime); } finally { Binder.restoreCallingIdentity(iden); } - checkTime(startTime, "getContentProviderImpl: after appDied (killedByAm)"); } } @@ -6895,9 +6898,8 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString() + " is crashing; detaching " + r); boolean lastRef = decProviderCountLocked(conn, cpr, token, stable); - checkTime(startTime, "getContentProviderImpl: before appDied"); - appDiedLocked(cpr.proc); - checkTime(startTime, "getContentProviderImpl: after appDied"); + mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc, + false, true, "getContentProviderImpl: %s", startTime); if (!lastRef) { // This wasn't the last ref our process had on // the provider... we have now been killed, bail. diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 7f1d5a33f56a..79fe61072a44 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -2909,6 +2909,12 @@ final class ActivityManagerShellCommand extends ShellCommand { final PlatformCompat platformCompat = (PlatformCompat) ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE); String toggleValue = getNextArgRequired(); + if (toggleValue.equals("reset-all")) { + final String packageName = getNextArgRequired(); + pw.println("Reset all changes for " + packageName + " to default value."); + platformCompat.clearOverrides(packageName); + return 0; + } long changeId; String changeIdString = getNextArgRequired(); try { @@ -3267,9 +3273,14 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" without restarting any processes."); pw.println(" write"); pw.println(" Write all pending state to storage."); - pw.println(" compat enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>"); - pw.println(" Toggles a change either by id or by name for <PACKAGE_NAME>."); - pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect)."); + pw.println(" compat [COMMAND] [...]: sub-commands for toggling app-compat changes."); + pw.println(" enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>"); + pw.println(" Toggles a change either by id or by name for <PACKAGE_NAME>."); + pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect)."); + pw.println(" reset-all <PACKAGE_NAME>"); + pw.println(" Removes all existing overrides for all changes for "); + pw.println(" <PACKAGE_NAME> (back to default behaviour)."); + pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect)."); pw.println(); Intent.printIntentArgsHelp(pw, ""); } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 51e1718d4c98..83a7341923fa 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -446,7 +446,8 @@ class AppErrors { RescueParty.noteAppCrash(mContext, r.uid); } - mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode()); + mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(), + PackageWatchdog.FAILURE_REASON_APP_CRASH); } final int relaunchReason = r != null @@ -900,7 +901,8 @@ class AppErrors { } // Notify PackageWatchdog without the lock held if (packageList != null) { - mPackageWatchdog.onPackageFailure(packageList); + mPackageWatchdog.onPackageFailure(packageList, + PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING); } } diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index 38030c248139..cf996a50d5c7 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -125,7 +125,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { // Keep the last WiFi stats so we can compute a delta. @GuardedBy("mWorkerLock") private WifiActivityEnergyInfo mLastInfo = - new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0, 0); + new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0); /** * Timestamp at which all external stats were last collected in diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java index 183e05979c5e..ebfc2a011e88 100644 --- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java +++ b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java @@ -66,9 +66,7 @@ final class CarUserSwitchingDialog extends UserSwitchingDialog { setCancelable(false); Resources res = getContext().getResources(); // Custom view due to alignment and font size requirements - // TODO (b/145021634): disabled because it's delaying user switch by 3 seconds - // getContext() - // .setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert_UserSwitchingDialog); + getContext().setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert_UserSwitchingDialog); View view = LayoutInflater.from(getContext()).inflate( R.layout.car_user_switching_dialog, null); diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS index 2f9a5c952659..7cc2e8eb2954 100644 --- a/services/core/java/com/android/server/am/OWNERS +++ b/services/core/java/com/android/server/am/OWNERS @@ -35,3 +35,5 @@ michaelwr@google.com narayan@google.com per-file SettingsToPropertiesMapper.java = omakoto@google.com, svetoslavganov@google.com, yamasani@google.com + +per-file CarUserSwitchingDialog.java = keunyoung@google.com, felipeal@google.com, gurunagarajan@google.com diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 2bb703545cad..32975d7792f5 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -78,6 +78,9 @@ import android.os.Trace; import android.os.UserHandle; import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; import android.text.TextUtils; import android.util.ArrayMap; import android.util.EventLog; @@ -283,6 +286,16 @@ public final class ProcessList { // lmkd reconnect delay in msecs private final static long LMDK_RECONNECT_DELAY_MS = 1000; + /** + * How long between a process kill and we actually receive its death recipient + */ + private static final long PROC_KILL_TIMEOUT = 2000; // 2 seconds; + + /** + * How long between polls to check if the given process is dead or not. + */ + private static final long PROC_DEATH_POLL_INTERVAL = 100; + ActivityManagerService mService = null; // To kill process groups asynchronously @@ -1421,7 +1434,7 @@ public final class ProcessList { if (app.pendingStart) { return true; } - long startTime = SystemClock.elapsedRealtime(); + long startTime = SystemClock.uptimeMillis(); if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) { checkSlow(startTime, "startProcess: removing from pids map"); mService.mPidsSelfLocked.remove(app); @@ -1856,7 +1869,7 @@ public final class ProcessList { boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord, boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) { - long startTime = SystemClock.elapsedRealtime(); + long startTime = SystemClock.uptimeMillis(); ProcessRecord app; if (!isolated) { app = getProcessRecordLocked(processName, info.uid, keepIfLarge); @@ -1917,10 +1930,9 @@ public final class ProcessList { // An application record is attached to a previous process, // clean it up now. if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app); - checkSlow(startTime, "startProcess: bad proc running, killing"); - ProcessList.killProcessGroup(app.uid, app.pid); - mService.handleAppDiedLocked(app, true, true); - checkSlow(startTime, "startProcess: done killing old proc"); + // do the killing + killProcAndWaitIfNecessaryLocked(app, true, app.uid == info.uid || app.isolated, + "startProcess: bad proc running, killing: %s", startTime); } if (app == null) { @@ -1961,6 +1973,70 @@ public final class ProcessList { return success ? app : null; } + /** + * A lite version of checking if a process is alive or not, by using kill(2) with signal 0. + * + * <p> + * Note that, zombie processes are stil "alive" in this case, use the {@link + * ActivityManagerService#isProcessAliveLocked} if zombie processes need to be excluded. + * </p> + */ + @GuardedBy("mService") + private boolean isProcessAliveLiteLocked(ProcessRecord app) { + try { + Os.kill(app.pid, 0); + } catch (ErrnoException e) { + return e.errno != OsConstants.ESRCH; + } + return true; + } + + /** + * Kill (if asked to) and wait for the given process died if necessary + * @param app - The process record to kill + * @param doKill - Kill the given process record + * @param wait - Wait for the death of the given process + * @param formatString - The log message for slow operation + * @param startTime - The start timestamp of the operation + */ + @GuardedBy("mService") + void killProcAndWaitIfNecessaryLocked(final ProcessRecord app, final boolean doKill, + final boolean wait, final String formatString, final long startTime) { + + checkSlow(startTime, String.format(formatString, "before appDied")); + + if (doKill) { + // do the killing + ProcessList.killProcessGroup(app.uid, app.pid); + } + + // wait for the death + if (wait) { + boolean isAlive = true; + // ideally we should use pidfd_open(2) but it's available on kernel 5.3 or later + + final long timeout = SystemClock.uptimeMillis() + PROC_KILL_TIMEOUT; + isAlive = isProcessAliveLiteLocked(app); + while (timeout > SystemClock.uptimeMillis() && isAlive) { + try { + Thread.sleep(PROC_DEATH_POLL_INTERVAL); + } catch (InterruptedException e) { + } + isAlive = isProcessAliveLiteLocked(app); + } + + if (isAlive) { + // Maybe the process goes into zombie, use an expensive API to check again. + if (mService.isProcessAliveLocked(app)) { + Slog.w(TAG, String.format(formatString, + "waiting for app killing timed out")); + } + } + } + + checkSlow(startTime, String.format(formatString, "after appDied")); + } + @GuardedBy("mService") private String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) { StringBuilder sb = null; diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java index bbf57728a20a..3dbf2c667c2f 100644 --- a/services/core/java/com/android/server/am/UserSwitchingDialog.java +++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java @@ -24,6 +24,7 @@ import android.os.Handler; import android.os.Message; import android.os.UserHandle; import android.os.UserManager; +import android.util.Slog; import android.view.LayoutInflater; import android.view.View; import android.view.ViewTreeObserver; @@ -46,6 +47,9 @@ class UserSwitchingDialog extends AlertDialog // Time to wait for the onWindowShown() callback before continuing the user switch private static final int WINDOW_SHOWN_TIMEOUT_MS = 3000; + // User switching doesn't happen that frequently, so it doesn't hurt to have it always on + protected static final boolean DEBUG = true; + private final ActivityManagerService mService; private final int mUserId; private static final int MSG_START_USER = 1; @@ -118,7 +122,7 @@ class UserSwitchingDialog extends AlertDialog @Override public void show() { - // Slog.v(TAG, "show called"); + if (DEBUG) Slog.d(TAG, "show called"); super.show(); final View decorView = getWindow().getDecorView(); if (decorView != null) { @@ -132,13 +136,14 @@ class UserSwitchingDialog extends AlertDialog @Override public void onWindowShown() { - // Slog.v(TAG, "onWindowShown called"); + if (DEBUG) Slog.d(TAG, "onWindowShown called"); startUser(); } void startUser() { synchronized (this) { if (!mStartedUser) { + Slog.i(TAG, "starting user " + mUserId); mService.mUserController.startUserInForeground(mUserId); dismiss(); mStartedUser = true; @@ -147,6 +152,8 @@ class UserSwitchingDialog extends AlertDialog decorView.getViewTreeObserver().removeOnWindowShownListener(this); } mHandler.removeMessages(MSG_START_USER); + } else { + Slog.i(TAG, "user " + mUserId + " already started"); } } } @@ -156,6 +163,8 @@ class UserSwitchingDialog extends AlertDialog public void handleMessage(Message msg) { switch (msg.what) { case MSG_START_USER: + Slog.w(TAG, "user switch window not shown in " + + WINDOW_SHOWN_TIMEOUT_MS + " ms"); startUser(); break; } diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 6010b1dc88c4..8144a7118096 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -24,6 +24,7 @@ import android.bluetooth.BluetoothProfile; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.media.AudioDeviceAddress; import android.media.AudioManager; import android.media.AudioRoutesInfo; import android.media.AudioSystem; @@ -400,6 +401,15 @@ import java.io.PrintWriter; } } + /*package*/ int setPreferredDeviceForStrategySync(int strategy, + @NonNull AudioDeviceAddress device) { + return mDeviceInventory.setPreferredDeviceForStrategySync(strategy, device); + } + + /*package*/ int removePreferredDeviceForStrategySync(int strategy) { + return mDeviceInventory.removePreferredDeviceForStrategySync(strategy); + } + //--------------------------------------------------------------------- // Communication with (to) AudioService //TODO check whether the AudioService methods are candidates to move here @@ -533,6 +543,15 @@ import java.io.PrintWriter; sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj); } + /*package*/ void postSaveSetPreferredDeviceForStrategy(int strategy, AudioDeviceAddress device) + { + sendILMsgNoDelay(MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy, device); + } + + /*package*/ void postSaveRemovePreferredDeviceForStrategy(int strategy) { + sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy); + } + //--------------------------------------------------------------------- // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory) // only call from a "handle"* method or "on"* method @@ -631,6 +650,7 @@ import java.io.PrintWriter; } else { pw.println("Message handler is null"); } + mDeviceInventory.dump(pw, prefix); } //--------------------------------------------------------------------- @@ -890,6 +910,15 @@ import java.io.PrintWriter; info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice); } } break; + case MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY: { + final int strategy = msg.arg1; + final AudioDeviceAddress device = (AudioDeviceAddress) msg.obj; + mDeviceInventory.onSaveSetPreferredDevice(strategy, device); + } break; + case MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY: { + final int strategy = msg.arg1; + mDeviceInventory.onSaveRemovePreferredDevice(strategy); + } break; default: Log.wtf(TAG, "Invalid message " + msg.what); } @@ -941,6 +970,8 @@ import java.io.PrintWriter; private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31; // a ScoClient died in BtHelper private static final int MSG_L_SCOCLIENT_DIED = 32; + private static final int MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY = 33; + private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34; private static boolean isMessageHandledUnderWakelock(int msgId) { diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index a2b3574880c4..661451b882cc 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -23,6 +23,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; import android.content.Intent; +import android.media.AudioDeviceAddress; import android.media.AudioDevicePort; import android.media.AudioFormat; import android.media.AudioManager; @@ -43,8 +44,10 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.Set; /** @@ -58,7 +61,10 @@ public class AudioDeviceInventory { // Actual list of connected devices // Key for map created from DeviceInfo.makeDeviceListKey() - private final ArrayMap<String, DeviceInfo> mConnectedDevices = new ArrayMap<>(); + private final LinkedHashMap<String, DeviceInfo> mConnectedDevices = new LinkedHashMap<>(); + + // List of preferred devices for strategies + private final ArrayMap<Integer, AudioDeviceAddress> mPreferredDevices = new ArrayMap<>(); private @NonNull AudioDeviceBroker mDeviceBroker; @@ -140,16 +146,23 @@ public class AudioDeviceInventory { } //------------------------------------------------------------ + /*package*/ void dump(PrintWriter pw, String prefix) { + pw.println("\n" + prefix + "Preferred devices for strategy:"); + mPreferredDevices.forEach((strategy, device) -> { + pw.println(" " + prefix + "strategy:" + strategy + " device:" + device); }); + } + + //------------------------------------------------------------ // Message handling from AudioDeviceBroker /** * Restore previously connected devices. Use in case of audio server crash * (see AudioService.onAudioServerDied() method) */ + // Always executed on AudioDeviceBroker message queue /*package*/ void onRestoreDevices() { synchronized (mConnectedDevices) { - for (int i = 0; i < mConnectedDevices.size(); i++) { - DeviceInfo di = mConnectedDevices.valueAt(i); + for (DeviceInfo di : mConnectedDevices.values()) { AudioSystem.setDeviceConnectionState( di.mDeviceType, AudioSystem.DEVICE_STATE_AVAILABLE, @@ -158,6 +171,11 @@ public class AudioDeviceInventory { di.mDeviceCodecFormat); } } + + synchronized (mPreferredDevices) { + mPreferredDevices.forEach((strategy, device) -> { + AudioSystem.setPreferredDeviceForStrategy(strategy, device); }); + } } // only public for mocking/spying @@ -432,9 +450,41 @@ public class AudioDeviceInventory { "android"); // reconnect } } + + /*package*/ void onSaveSetPreferredDevice(int strategy, @NonNull AudioDeviceAddress device) { + mPreferredDevices.put(strategy, device); + } + + /*package*/ void onSaveRemovePreferredDevice(int strategy) { + mPreferredDevices.remove(strategy); + } + //------------------------------------------------------------ // + /*package*/ int setPreferredDeviceForStrategySync(int strategy, + @NonNull AudioDeviceAddress device) { + final long identity = Binder.clearCallingIdentity(); + final int status = AudioSystem.setPreferredDeviceForStrategy(strategy, device); + Binder.restoreCallingIdentity(identity); + + if (status == AudioSystem.SUCCESS) { + mDeviceBroker.postSaveSetPreferredDeviceForStrategy(strategy, device); + } + return status; + } + + /*package*/ int removePreferredDeviceForStrategySync(int strategy) { + final long identity = Binder.clearCallingIdentity(); + final int status = AudioSystem.removePreferredDeviceForStrategy(strategy); + Binder.restoreCallingIdentity(identity); + + if (status == AudioSystem.SUCCESS) { + mDeviceBroker.postSaveRemovePreferredDeviceForStrategy(strategy); + } + return status; + } + /** * Implements the communication with AudioSystem to (dis)connect a device in the native layers * @param connect true if connection @@ -799,11 +849,10 @@ public class AudioDeviceInventory { } int delay = 0; Set<Integer> devices = new HashSet<>(); - for (int i = 0; i < mConnectedDevices.size(); i++) { - int dev = mConnectedDevices.valueAt(i).mDeviceType; - if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) - && BECOMING_NOISY_INTENT_DEVICES_SET.contains(dev)) { - devices.add(dev); + for (DeviceInfo di : mConnectedDevices.values()) { + if (((di.mDeviceType & AudioSystem.DEVICE_BIT_IN) == 0) + && BECOMING_NOISY_INTENT_DEVICES_SET.contains(di.mDeviceType)) { + devices.add(di.mDeviceType); } } if (musicDevice == AudioSystem.DEVICE_NONE) { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 4bf1de66b408..1a62eb26580c 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -63,6 +63,8 @@ import android.hardware.input.InputManager; import android.hardware.usb.UsbManager; import android.hidl.manager.V1_0.IServiceManager; import android.media.AudioAttributes; +import android.media.AudioDeviceAddress; +import android.media.AudioDeviceInfo; import android.media.AudioFocusInfo; import android.media.AudioFocusRequest; import android.media.AudioFormat; @@ -1633,6 +1635,60 @@ public class AudioService extends IAudioService.Stub /////////////////////////////////////////////////////////////////////////// // IPC methods /////////////////////////////////////////////////////////////////////////// + /** @see AudioManager#setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceInfo) */ + public int setPreferredDeviceForStrategy(int strategy, AudioDeviceAddress device) { + if (device == null) { + return AudioSystem.ERROR; + } + enforceModifyAudioRoutingPermission(); + final String logString = String.format( + "setPreferredDeviceForStrategy u/pid:%d/%d strat:%d dev:%s", + Binder.getCallingUid(), Binder.getCallingPid(), strategy, device.toString()); + sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG)); + if (device.getRole() == AudioDeviceAddress.ROLE_INPUT) { + Log.e(TAG, "Unsupported input routing in " + logString); + return AudioSystem.ERROR; + } + + final int status = mDeviceBroker.setPreferredDeviceForStrategySync(strategy, device); + if (status != AudioSystem.SUCCESS) { + Log.e(TAG, String.format("Error %d in %s)", status, logString)); + } + + return status; + } + + /** @see AudioManager#removePreferredDeviceForStrategy(AudioProductStrategy) */ + public int removePreferredDeviceForStrategy(int strategy) { + enforceModifyAudioRoutingPermission(); + final String logString = + String.format("removePreferredDeviceForStrategy strat:%d", strategy); + sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG)); + + final int status = mDeviceBroker.removePreferredDeviceForStrategySync(strategy); + if (status != AudioSystem.SUCCESS) { + Log.e(TAG, String.format("Error %d in %s)", status, logString)); + } + return status; + } + + /** @see AudioManager#getPreferredDeviceForStrategy(AudioProductStrategy) */ + public AudioDeviceAddress getPreferredDeviceForStrategy(int strategy) { + enforceModifyAudioRoutingPermission(); + AudioDeviceAddress[] devices = new AudioDeviceAddress[1]; + final long identity = Binder.clearCallingIdentity(); + final int status = AudioSystem.getPreferredDeviceForStrategy(strategy, devices); + Binder.restoreCallingIdentity(identity); + if (status != AudioSystem.SUCCESS) { + Log.e(TAG, String.format("Error %d in getPreferredDeviceForStrategy(%d)", + status, strategy)); + return null; + } else { + return devices[0]; + } + } + + /** @see AudioManager#adjustVolume(int, int) */ public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, String callingPackage, String caller) { diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 9f1a6bd15ac3..36332c0ad25c 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -295,6 +295,7 @@ public class BtHelper { && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) { mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; } + broadcast = false; break; default: // do not broadcast CONNECTING or invalid state diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java index 27f11ffa60ce..1b1c54682255 100644 --- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java +++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java @@ -31,8 +31,6 @@ import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.app.IBatteryStats; -import com.android.internal.telephony.IccCardConstants; -import com.android.internal.telephony.TelephonyIntents; import com.android.server.am.BatteryStatsService; public class DataConnectionStats extends BroadcastReceiver { @@ -44,7 +42,7 @@ public class DataConnectionStats extends BroadcastReceiver { private final Handler mListenerHandler; private final PhoneStateListener mPhoneStateListener; - private IccCardConstants.State mSimState = IccCardConstants.State.READY; + private int mSimState = TelephonyManager.SIM_STATE_READY; private SignalStrength mSignalStrength; private ServiceState mServiceState; private int mDataState = TelephonyManager.DATA_DISCONNECTED; @@ -66,7 +64,7 @@ public class DataConnectionStats extends BroadcastReceiver { | PhoneStateListener.LISTEN_DATA_ACTIVITY); IntentFilter filter = new IntentFilter(); - filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + filter.addAction(Intent.ACTION_SIM_STATE_CHANGED); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(ConnectivityManager.INET_CONDITION_ACTION); mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler); @@ -75,7 +73,7 @@ public class DataConnectionStats extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); - if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { + if (action.equals(Intent.ACTION_SIM_STATE_CHANGED)) { updateSimState(intent); notePhoneDataConnectionState(); } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) || @@ -88,8 +86,8 @@ public class DataConnectionStats extends BroadcastReceiver { if (mServiceState == null) { return; } - boolean simReadyOrUnknown = mSimState == IccCardConstants.State.READY - || mSimState == IccCardConstants.State.UNKNOWN; + boolean simReadyOrUnknown = mSimState == TelephonyManager.SIM_STATE_READY + || mSimState == TelephonyManager.SIM_STATE_UNKNOWN; boolean visible = (simReadyOrUnknown || isCdma()) // we only check the sim state for GSM && hasService() && mDataState == TelephonyManager.DATA_CONNECTED; @@ -105,23 +103,23 @@ public class DataConnectionStats extends BroadcastReceiver { } private final void updateSimState(Intent intent) { - String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); - if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { - mSimState = IccCardConstants.State.ABSENT; - } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) { - mSimState = IccCardConstants.State.READY; - } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { + String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE); + if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) { + mSimState = TelephonyManager.SIM_STATE_ABSENT; + } else if (Intent.SIM_STATE_READY.equals(stateExtra)) { + mSimState = TelephonyManager.SIM_STATE_READY; + } else if (Intent.SIM_STATE_LOCKED.equals(stateExtra)) { final String lockedReason = - intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); - if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { - mSimState = IccCardConstants.State.PIN_REQUIRED; - } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { - mSimState = IccCardConstants.State.PUK_REQUIRED; + intent.getStringExtra(Intent.EXTRA_SIM_LOCKED_REASON); + if (Intent.SIM_LOCKED_ON_PIN.equals(lockedReason)) { + mSimState = TelephonyManager.SIM_STATE_PIN_REQUIRED; + } else if (Intent.SIM_LOCKED_ON_PUK.equals(lockedReason)) { + mSimState = TelephonyManager.SIM_STATE_PUK_REQUIRED; } else { - mSimState = IccCardConstants.State.NETWORK_LOCKED; + mSimState = TelephonyManager.SIM_STATE_NETWORK_LOCKED; } } else { - mSimState = IccCardConstants.State.UNKNOWN; + mSimState = TelephonyManager.SIM_STATE_UNKNOWN; } } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index bb7f86233a40..5e085ca293a4 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -291,13 +291,18 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { * * <p>If {@link NetworkMonitor#notifyNetworkCapabilitiesChanged(NetworkCapabilities)} fails, * the exception is logged but not reported to callers. + * + * @return the old capabilities of this network. */ - public void setNetworkCapabilities(NetworkCapabilities nc) { + public synchronized NetworkCapabilities getAndSetNetworkCapabilities( + @NonNull final NetworkCapabilities nc) { + final NetworkCapabilities oldNc = networkCapabilities; networkCapabilities = nc; final NetworkMonitorManager nm = mNetworkMonitor; if (nm != null) { nm.notifyNetworkCapabilitiesChanged(nc); } + return oldNc; } public ConnectivityService connService() { diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index 31632dc007a5..177e2d8b5fa2 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -41,6 +41,7 @@ import android.util.MathUtils; import android.util.Slog; import android.util.TimeUtils; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.server.EventLogTags; @@ -215,7 +216,26 @@ class AutomaticBrightnessController { private IActivityTaskManager mActivityTaskManager; private PackageManager mPackageManager; - public AutomaticBrightnessController(Callbacks callbacks, Looper looper, + private final Injector mInjector; + + AutomaticBrightnessController(Callbacks callbacks, Looper looper, + SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper, + int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor, + int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig, + long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig, + HysteresisLevels ambientBrightnessThresholds, + HysteresisLevels screenBrightnessThresholds, long shortTermModelTimeout, + PackageManager packageManager) { + this(new Injector(), callbacks, looper, sensorManager, lightSensor, mapper, + lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor, + lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig, + darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig, + ambientBrightnessThresholds, screenBrightnessThresholds, shortTermModelTimeout, + packageManager); + } + + @VisibleForTesting + AutomaticBrightnessController(Injector injector, Callbacks callbacks, Looper looper, SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper, int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig, @@ -223,6 +243,7 @@ class AutomaticBrightnessController { HysteresisLevels ambientBrightnessThresholds, HysteresisLevels screenBrightnessThresholds, long shortTermModelTimeout, PackageManager packageManager) { + mInjector = injector; mCallbacks = callbacks; mSensorManager = sensorManager; mBrightnessMapper = mapper; @@ -725,8 +746,8 @@ class AutomaticBrightnessController { float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName, mForegroundAppCategory); - int newScreenAutoBrightness = - clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON)); + int newScreenAutoBrightness = Math.round(clampScreenBrightness( + value * PowerManager.BRIGHTNESS_ON)); // If screenAutoBrightness is set, we should have screen{Brightening,Darkening}Threshold, // in which case we ignore the new screen brightness if it doesn't differ enough from the @@ -750,10 +771,10 @@ class AutomaticBrightnessController { } mScreenAutoBrightness = newScreenAutoBrightness; - mScreenBrighteningThreshold = - mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness); - mScreenDarkeningThreshold = - mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness); + mScreenBrighteningThreshold = clampScreenBrightness( + mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness)); + mScreenDarkeningThreshold = clampScreenBrightness( + mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness)); if (sendUpdate) { mCallbacks.updateBrightness(); @@ -761,7 +782,7 @@ class AutomaticBrightnessController { } } - private int clampScreenBrightness(int value) { + private float clampScreenBrightness(float value) { return MathUtils.constrain(value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum); } @@ -839,7 +860,7 @@ class AutomaticBrightnessController { } // The ActivityTaskManager's lock tends to get contended, so this is done in a background // thread and applied via this thread's handler synchronously. - BackgroundThread.getHandler().post(new Runnable() { + mInjector.getBackgroundThreadHandler().post(new Runnable() { public void run() { try { // The foreground app is the top activity of the focused tasks stack. @@ -965,6 +986,9 @@ class AutomaticBrightnessController { private int mCount; public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) { + if (lightSensorRate <= 0) { + throw new IllegalArgumentException("lightSensorRate must be above 0"); + } mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate); mRingLux = new float[mCapacity]; mRingTime = new long[mCapacity]; @@ -1076,4 +1100,10 @@ class AutomaticBrightnessController { return index; } } + + public static class Injector { + public Handler getBackgroundThreadHandler() { + return BackgroundThread.getHandler(); + } + } } diff --git a/services/core/java/com/android/server/display/HysteresisLevels.java b/services/core/java/com/android/server/display/HysteresisLevels.java index 2db1d03893d2..f0a505d4d818 100644 --- a/services/core/java/com/android/server/display/HysteresisLevels.java +++ b/services/core/java/com/android/server/display/HysteresisLevels.java @@ -18,13 +18,16 @@ package com.android.server.display; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; + import java.io.PrintWriter; import java.util.Arrays; /** * A helper class for handling access to illuminance hysteresis level values. */ -final class HysteresisLevels { +@VisibleForTesting +public class HysteresisLevels { private static final String TAG = "HysteresisLevels"; // Default hysteresis constraints for brightening or darkening. @@ -60,7 +63,7 @@ final class HysteresisLevels { /** * Return the brightening hysteresis threshold for the given value level. */ - float getBrighteningThreshold(float value) { + public float getBrighteningThreshold(float value) { float brightConstant = getReferenceLevel(value, mBrighteningThresholds); float brightThreshold = value * (1.0f + brightConstant); if (DEBUG) { @@ -73,7 +76,7 @@ final class HysteresisLevels { /** * Return the darkening hysteresis threshold for the given value level. */ - float getDarkeningThreshold(float value) { + public float getDarkeningThreshold(float value) { float darkConstant = getReferenceLevel(value, mDarkeningThresholds); float darkThreshold = value * (1.0f - darkConstant); if (DEBUG) { diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index c4ea81a83fdb..1d7c942e8224 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -848,7 +848,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { int[] ports = res.getIntArray( com.android.internal.R.array.config_localPrivateDisplayPorts); if (ports != null) { - int port = physicalAddress.getPort(); + int port = Byte.toUnsignedInt(physicalAddress.getPort()); for (int p : ports) { if (p == port) { return true; diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerService.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerService.java new file mode 100644 index 000000000000..005fb696b089 --- /dev/null +++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerService.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity; + +import android.content.Context; + +import com.android.server.SystemService; + +/** + * Service that manages app integrity rules and verifications. + * + * @hide + */ +public class AppIntegrityManagerService extends SystemService { + + private Context mContext; + private AppIntegrityManagerServiceImpl mService; + + public AppIntegrityManagerService(Context context) { + super(context); + mContext = context; + } + + @Override + public void onStart() { + mService = new AppIntegrityManagerServiceImpl(mContext); + // TODO: define and publish a binder service. + } +} diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java new file mode 100644 index 000000000000..39c1b8535565 --- /dev/null +++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity; + +import static android.content.Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION; +import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; +import android.os.Handler; +import android.os.HandlerThread; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; + +/** Implementation of {@link AppIntegrityManagerService}. */ +class AppIntegrityManagerServiceImpl { + private static final String TAG = "AppIntegrityManagerServiceImpl"; + + private final Context mContext; + private final Handler mHandler; + private final PackageManagerInternal mPackageManagerInternal; + + AppIntegrityManagerServiceImpl(Context context) { + mContext = context; + + HandlerThread handlerThread = new HandlerThread("AppIntegrityManagerServiceHandler"); + handlerThread.start(); + mHandler = handlerThread.getThreadHandler(); + + mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); + + IntentFilter integrityVerificationFilter = new IntentFilter(); + integrityVerificationFilter.addAction(ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION); + + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (!ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION.equals( + intent.getAction())) { + return; + } + mHandler.post(() -> handleIntegrityVerification(intent)); + } + }, + integrityVerificationFilter, + /* broadcastPermission= */ null, + mHandler); + } + + // protected broadcasts cannot be sent in the test. + @VisibleForTesting + void handleIntegrityVerification(Intent intent) { + int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1); + // TODO: implement this method. + Slog.i(TAG, "Received integrity verification intent " + intent.toString()); + mPackageManagerInternal.setIntegrityVerificationResult( + verificationId, PackageManager.VERIFICATION_ALLOW); + } +} diff --git a/services/core/java/com/android/server/integrity/model/BitInputStream.java b/services/core/java/com/android/server/integrity/model/BitInputStream.java index 09bc7e8b9861..e768fe6626ac 100644 --- a/services/core/java/com/android/server/integrity/model/BitInputStream.java +++ b/services/core/java/com/android/server/integrity/model/BitInputStream.java @@ -16,15 +16,29 @@ package com.android.server.integrity.model; +import java.io.IOException; +import java.io.InputStream; + /** A wrapper class for reading a stream of bits. */ public class BitInputStream { - private byte[] mRuleBytes; private long mBitPointer; + private boolean mReadFromStream; + + private byte[] mRuleBytes; + private InputStream mRuleInputStream; + + private byte mCurrentRuleByte; public BitInputStream(byte[] ruleBytes) { this.mRuleBytes = ruleBytes; this.mBitPointer = 0; + this.mReadFromStream = false; + } + + public BitInputStream(InputStream ruleInputStream) { + this.mRuleInputStream = ruleInputStream; + this.mReadFromStream = true; } /** @@ -33,34 +47,43 @@ public class BitInputStream { * @param numOfBits The number of bits to read. * @return The value read from the stream. */ - public int getNext(int numOfBits) { + public int getNext(int numOfBits) throws IOException { int component = 0; int count = 0; - int idx = (int) (mBitPointer / 8); - int offset = 7 - (int) (mBitPointer % 8); - while (count++ < numOfBits) { - if (idx >= mRuleBytes.length) { - throw new IllegalArgumentException(String.format("Invalid byte index: %d", idx)); + if (mBitPointer % 8 == 0) { + mCurrentRuleByte = getNextByte(); } + int offset = 7 - (int) (mBitPointer % 8); component <<= 1; - component |= (mRuleBytes[idx] >>> offset) & 1; + component |= (mCurrentRuleByte >>> offset) & 1; - offset--; - if (offset == -1) { - idx++; - offset = 7; - } + mBitPointer++; } - mBitPointer += numOfBits; return component; } /** Check if there are bits left in the stream. */ - public boolean hasNext() { - return mBitPointer / 8 < mRuleBytes.length; + public boolean hasNext() throws IOException { + if (mReadFromStream) { + return mRuleInputStream.available() > 0; + } else { + return mBitPointer / 8 < mRuleBytes.length; + } + } + + private byte getNextByte() throws IOException { + if (mReadFromStream) { + return (byte) mRuleInputStream.read(); + } else { + int idx = (int) (mBitPointer / 8); + if (idx >= mRuleBytes.length) { + throw new IllegalArgumentException(String.format("Invalid byte index: %d", idx)); + } + return mRuleBytes[idx]; + } } } diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java index 8aa0751af11c..3ef45a637bc1 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java +++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java @@ -36,6 +36,7 @@ import android.content.integrity.Rule; import com.android.server.integrity.model.BitInputStream; +import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -56,15 +57,14 @@ public class RuleBinaryParser implements RuleParser { @Override public List<Rule> parse(InputStream inputStream) throws RuleParseException { try { - byte[] ruleBytes = new byte[inputStream.available()]; - inputStream.read(ruleBytes); - return parse(ruleBytes); + BitInputStream bitInputStream = new BitInputStream(inputStream); + return parseRules(bitInputStream); } catch (Exception e) { throw new RuleParseException(e.getMessage(), e); } } - private List<Rule> parseRules(BitInputStream bitInputStream) { + private List<Rule> parseRules(BitInputStream bitInputStream) throws IOException { List<Rule> parsedRules = new ArrayList<>(); // Read the rule binary file format version. @@ -79,7 +79,7 @@ public class RuleBinaryParser implements RuleParser { return parsedRules; } - private Rule parseRule(BitInputStream bitInputStream) { + private Rule parseRule(BitInputStream bitInputStream) throws IOException { Formula formula = parseFormula(bitInputStream); int effect = bitInputStream.getNext(EFFECT_BITS); @@ -90,7 +90,7 @@ public class RuleBinaryParser implements RuleParser { return new Rule(formula, effect); } - private Formula parseFormula(BitInputStream bitInputStream) { + private Formula parseFormula(BitInputStream bitInputStream) throws IOException { int separator = bitInputStream.getNext(SEPARATOR_BITS); switch (separator) { case ATOMIC_FORMULA_START: @@ -105,7 +105,7 @@ public class RuleBinaryParser implements RuleParser { } } - private CompoundFormula parseCompoundFormula(BitInputStream bitInputStream) { + private CompoundFormula parseCompoundFormula(BitInputStream bitInputStream) throws IOException { int connector = bitInputStream.getNext(CONNECTOR_BITS); List<Formula> formulas = new ArrayList<>(); @@ -118,7 +118,7 @@ public class RuleBinaryParser implements RuleParser { return new CompoundFormula(connector, formulas); } - private AtomicFormula parseAtomicFormula(BitInputStream bitInputStream) { + private AtomicFormula parseAtomicFormula(BitInputStream bitInputStream) throws IOException { int key = bitInputStream.getNext(KEY_BITS); int operator = bitInputStream.getNext(OPERATOR_BITS); diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java index b988fd4c40f1..fdbb7d9df293 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java @@ -127,7 +127,7 @@ public class RuleBinarySerializer implements RuleSerializer { bitOutputStream.setNext(SEPARATOR_BITS, ATOMIC_FORMULA_START); bitOutputStream.setNext(KEY_BITS, atomicFormula.getKey()); - if (atomicFormula instanceof AtomicFormula.StringAtomicFormula) { + if (atomicFormula.getTag() == AtomicFormula.STRING_ATOMIC_FORMULA_TAG) { AtomicFormula.StringAtomicFormula stringAtomicFormula = (AtomicFormula.StringAtomicFormula) atomicFormula; bitOutputStream.setNext(OPERATOR_BITS, AtomicFormula.EQ); @@ -135,7 +135,7 @@ public class RuleBinarySerializer implements RuleSerializer { stringAtomicFormula.getValue(), stringAtomicFormula.getIsHashedValue(), bitOutputStream); - } else if (atomicFormula instanceof AtomicFormula.IntAtomicFormula) { + } else if (atomicFormula.getTag() == AtomicFormula.INT_ATOMIC_FORMULA_TAG) { AtomicFormula.IntAtomicFormula intAtomicFormula = (AtomicFormula.IntAtomicFormula) atomicFormula; bitOutputStream.setNext(OPERATOR_BITS, intAtomicFormula.getOperator()); @@ -143,7 +143,7 @@ public class RuleBinarySerializer implements RuleSerializer { String.valueOf(intAtomicFormula.getValue()), /* isHashedValue= */ false, bitOutputStream); - } else if (atomicFormula instanceof AtomicFormula.BooleanAtomicFormula) { + } else if (atomicFormula.getTag() == AtomicFormula.BOOLEAN_ATOMIC_FORMULA_TAG) { AtomicFormula.BooleanAtomicFormula booleanAtomicFormula = (AtomicFormula.BooleanAtomicFormula) atomicFormula; bitOutputStream.setNext(OPERATOR_BITS, AtomicFormula.EQ); diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java new file mode 100644 index 000000000000..4d3961df6092 --- /dev/null +++ b/services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity.serializer; + +import android.annotation.IntDef; +import android.content.integrity.AtomicFormula; +import android.content.integrity.CompoundFormula; +import android.content.integrity.Formula; +import android.content.integrity.Rule; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** A helper class for identifying the indexing type of a given rule. */ +public class RuleIndexTypeIdentifier { + + static final int NOT_INDEXED = 0; + static final int PACKAGE_NAME_INDEXED = 1; + static final int APP_CERTIFICATE_INDEXED = 2; + + /** Represents which indexed file the rule should be located. */ + @IntDef( + value = { + NOT_INDEXED, + PACKAGE_NAME_INDEXED, + APP_CERTIFICATE_INDEXED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface IndexType { + } + + /** Determines the indexing file type that a given rule should be located at. */ + public static int getIndexType(Rule rule) { + if (rule == null) { + throw new IllegalArgumentException("Indexing type cannot be determined for null rule."); + } + return getIndexType(rule.getFormula()); + } + + private static int getIndexType(Formula formula) { + if (formula == null) { + throw new IllegalArgumentException( + "Indexing type cannot be determined for null formula."); + } + + switch (formula.getTag()) { + case Formula.COMPOUND_FORMULA_TAG: + return getIndexTypeForCompoundFormula((CompoundFormula) formula); + case Formula.STRING_ATOMIC_FORMULA_TAG: + return getIndexTypeForAtomicStringFormula((AtomicFormula) formula); + case Formula.INT_ATOMIC_FORMULA_TAG: + case Formula.BOOLEAN_ATOMIC_FORMULA_TAG: + // Package name and app certificate related formulas are string atomic formulas. + return NOT_INDEXED; + default: + throw new IllegalArgumentException( + String.format("Invalid formula tag type: %s", formula.getTag())); + } + } + + private static int getIndexTypeForCompoundFormula(CompoundFormula compoundFormula) { + int connector = compoundFormula.getConnector(); + List<Formula> formulas = compoundFormula.getFormulas(); + + switch (connector) { + case CompoundFormula.NOT: + // Having a NOT operator in the indexing messes up the indexing; e.g., deny + // installation if app certificate is NOT X (should not be indexed with app cert + // X). We will not keep these rules indexed. + return NOT_INDEXED; + case CompoundFormula.AND: + case CompoundFormula.OR: + Set<Integer> indexingTypesForAllFormulas = + formulas.stream() + .map(formula -> getIndexType(formula)) + .collect(Collectors.toSet()); + if (indexingTypesForAllFormulas.contains(PACKAGE_NAME_INDEXED)) { + return PACKAGE_NAME_INDEXED; + } else if (indexingTypesForAllFormulas.contains(APP_CERTIFICATE_INDEXED)) { + return APP_CERTIFICATE_INDEXED; + } else { + return NOT_INDEXED; + } + default: + return NOT_INDEXED; + } + } + + private static int getIndexTypeForAtomicStringFormula(AtomicFormula atomicFormula) { + switch (atomicFormula.getKey()) { + case AtomicFormula.PACKAGE_NAME: + return PACKAGE_NAME_INDEXED; + case AtomicFormula.APP_CERTIFICATE: + return APP_CERTIFICATE_INDEXED; + default: + return NOT_INDEXED; + } + } +} + diff --git a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java index 72068ceeb4f0..cfe50c6c8ac9 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java @@ -127,7 +127,7 @@ public class RuleXmlSerializer implements RuleSerializer { xmlSerializer.startTag(NAMESPACE, ATOMIC_FORMULA_TAG); serializeAttributeValue( KEY_ATTRIBUTE, String.valueOf(atomicFormula.getKey()), xmlSerializer); - if (atomicFormula instanceof AtomicFormula.StringAtomicFormula) { + if (atomicFormula.getTag() == AtomicFormula.STRING_ATOMIC_FORMULA_TAG) { serializeAttributeValue( VALUE_ATTRIBUTE, ((AtomicFormula.StringAtomicFormula) atomicFormula).getValue(), @@ -137,7 +137,7 @@ public class RuleXmlSerializer implements RuleSerializer { String.valueOf( ((AtomicFormula.StringAtomicFormula) atomicFormula).getIsHashedValue()), xmlSerializer); - } else if (atomicFormula instanceof AtomicFormula.IntAtomicFormula) { + } else if (atomicFormula.getTag() == AtomicFormula.INT_ATOMIC_FORMULA_TAG) { serializeAttributeValue( OPERATOR_ATTRIBUTE, String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getOperator()), @@ -146,7 +146,7 @@ public class RuleXmlSerializer implements RuleSerializer { VALUE_ATTRIBUTE, String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getValue()), xmlSerializer); - } else if (atomicFormula instanceof AtomicFormula.BooleanAtomicFormula) { + } else if (atomicFormula.getTag() == AtomicFormula.BOOLEAN_ATOMIC_FORMULA_TAG) { serializeAttributeValue( VALUE_ATTRIBUTE, String.valueOf(((AtomicFormula.BooleanAtomicFormula) atomicFormula).getValue()), diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 557ba54b536d..f913ba337071 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -531,8 +531,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId(); - String mccMnc = SubscriptionManager.isValidSubscriptionId(ddSubId) - ? phone.getSimOperator(ddSubId) : phone.getSimOperator(); + if (SubscriptionManager.isValidSubscriptionId(ddSubId)) { + phone = phone.createForSubscriptionId(ddSubId); + } + String mccMnc = phone.getSimOperator(); boolean isKeepLppProfile = false; if (!TextUtils.isEmpty(mccMnc)) { if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc); @@ -1913,24 +1915,17 @@ public class GnssLocationProvider extends AbstractLocationProvider implements String setId = null; int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId(); + if (SubscriptionManager.isValidSubscriptionId(ddSubId)) { + phone = phone.createForSubscriptionId(ddSubId); + } if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { - if (SubscriptionManager.isValidSubscriptionId(ddSubId)) { - setId = phone.getSubscriberId(ddSubId); - } - if (setId == null) { - setId = phone.getSubscriberId(); - } + setId = phone.getSubscriberId(); if (setId != null) { // This means the framework has the SIM card. type = AGPS_SETID_TYPE_IMSI; } } else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { - if (SubscriptionManager.isValidSubscriptionId(ddSubId)) { - setId = phone.getLine1Number(ddSubId); - } - if (setId == null) { - setId = phone.getLine1Number(); - } + setId = phone.getLine1Number(); if (setId != null) { // This means the framework has the SIM card. type = AGPS_SETID_TYPE_MSISDN; diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java index ea4f9c456856..dd522b95a938 100644 --- a/services/core/java/com/android/server/location/GnssVisibilityControl.java +++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java @@ -637,7 +637,7 @@ class GnssVisibilityControl { return new Notification.Builder(context, SystemNotificationChannels.NETWORK_ALERTS) .setSmallIcon(com.android.internal.R.drawable.stat_sys_gps_on) .setWhen(0) - .setOngoing(true) + .setOngoing(false) .setAutoCancel(true) .setColor(context.getColor( com.android.internal.R.color.system_notification_accent_color)) diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 83b62159f9b0..ec4aedd01cea 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -379,7 +379,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!"); try (LockscreenCredential unifiedProfilePassword = generateRandomProfilePassword()) { setLockCredentialInternal(unifiedProfilePassword, managedUserPassword, managedUserId, - false, /* isLockTiedToParent= */ true); + /* isLockTiedToParent= */ true); tieProfileLockToParent(managedUserId, unifiedProfilePassword); } } @@ -1473,17 +1473,12 @@ public class LockSettingsService extends ILockSettings.Stub { setLockCredentialInternal(LockscreenCredential.createNone(), profilePasswordMap.get(managedUserId), managedUserId, - false, /* isLockTiedToParent= */ true); + /* isLockTiedToParent= */ true); + mStorage.removeChildProfileLock(managedUserId); + removeKeystoreProfileKey(managedUserId); } else { - Slog.wtf(TAG, "clear tied profile challenges, but no password supplied."); - // Attempt an untrusted reset by supplying an empty credential. - setLockCredentialInternal(LockscreenCredential.createNone(), - LockscreenCredential.createNone(), - managedUserId, - true, /* isLockTiedToParent= */ true); + Slog.wtf(TAG, "Attempt to clear tied challenge, but no password supplied."); } - mStorage.removeChildProfileLock(managedUserId); - removeKeystoreProfileKey(managedUserId); } } } @@ -1567,7 +1562,7 @@ public class LockSettingsService extends ILockSettings.Stub { // should call setLockCredentialInternal. @Override public boolean setLockCredential(LockscreenCredential credential, - LockscreenCredential savedCredential, int userId, boolean allowUntrustedChange) { + LockscreenCredential savedCredential, int userId) { if (!mLockPatternUtils.hasSecureLockScreen()) { throw new UnsupportedOperationException( @@ -1576,7 +1571,7 @@ public class LockSettingsService extends ILockSettings.Stub { checkWritePermission(userId); synchronized (mSeparateChallengeLock) { if (!setLockCredentialInternal(credential, savedCredential, - userId, allowUntrustedChange, /* isLockTiedToParent= */ false)) { + userId, /* isLockTiedToParent= */ false)) { return false; } setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null); @@ -1598,14 +1593,13 @@ public class LockSettingsService extends ILockSettings.Stub { * credentials are being tied to its parent's credentials. */ private boolean setLockCredentialInternal(LockscreenCredential credential, - LockscreenCredential savedCredential, int userId, - boolean allowUntrustedChange, boolean isLockTiedToParent) { + LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) { Preconditions.checkNotNull(credential); Preconditions.checkNotNull(savedCredential); synchronized (mSpManager) { if (isSyntheticPasswordBasedCredentialLocked(userId)) { return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId, - allowUntrustedChange, isLockTiedToParent); + isLockTiedToParent); } } @@ -1653,7 +1647,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (shouldMigrateToSyntheticPasswordLocked(userId)) { initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential, userId); return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId, - allowUntrustedChange, isLockTiedToParent); + isLockTiedToParent); } } if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId); @@ -2075,7 +2069,7 @@ public class LockSettingsService extends ILockSettings.Stub { } if (shouldReEnroll) { setLockCredentialInternal(credential, credential, - userId, false, /* isLockTiedToParent= */ false); + userId, /* isLockTiedToParent= */ false); } else { // Now that we've cleared of all required GK migration, let's do the final // migration to synthetic password. @@ -2210,7 +2204,6 @@ public class LockSettingsService extends ILockSettings.Stub { Slog.i(TAG, "RemoveUser: " + userId); mSpManager.removeUser(userId); mStrongAuth.removeUser(userId); - tryRemoveUserFromSpCacheLater(userId); final KeyStore ks = KeyStore.getInstance(); ks.onUserRemoved(userId); @@ -2471,25 +2464,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } - /** - * A user's synthetic password does not change so it must be cached in certain circumstances to - * enable untrusted credential reset. - * - * Untrusted credential reset will be removed in a future version (b/68036371) at which point - * this cache is no longer needed as the SP will always be known when changing the user's - * credential. - */ - @GuardedBy("mSpManager") - private SparseArray<AuthenticationToken> mSpCache = new SparseArray<>(); - private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) { - // Preemptively cache the SP and then try to remove it in a handler. - Slog.i(TAG, "Caching SP for user " + userId); - synchronized (mSpManager) { - mSpCache.put(userId, auth); - } - tryRemoveUserFromSpCacheLater(userId); - if (mInjector.isGsiRunning()) { Slog.w(TAG, "AuthSecret disabled in GSI"); return; @@ -2510,42 +2485,6 @@ public class LockSettingsService extends ILockSettings.Stub { } } - private void tryRemoveUserFromSpCacheLater(@UserIdInt int userId) { - mHandler.post(() -> { - if (!shouldCacheSpForUser(userId)) { - // The transition from 'should not cache' to 'should cache' can only happen if - // certain admin apps are installed after provisioning e.g. via adb. This is not - // a common case and we do not seamlessly support; it may result in the SP not - // being cached when it is needed. The cache can be re-populated by verifying - // the credential again. - Slog.i(TAG, "Removing SP from cache for user " + userId); - synchronized (mSpManager) { - mSpCache.remove(userId); - } - } - }); - } - - /** Do not hold any of the locks from this service when calling. */ - private boolean shouldCacheSpForUser(@UserIdInt int userId) { - // Before the user setup has completed, an admin could be installed that requires the SP to - // be cached (see below). - if (Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.USER_SETUP_COMPLETE, 0, userId) == 0) { - return true; - } - - // If the user has an admin which can perform an untrusted credential reset, the SP needs to - // be cached. If there isn't a DevicePolicyManager then there can't be an admin in the first - // place so caching is not necessary. - final DevicePolicyManagerInternal dpmi = LocalServices.getService( - DevicePolicyManagerInternal.class); - if (dpmi == null) { - return false; - } - return dpmi.canUserHaveUntrustedCredentialReset(userId); - } - /** * Precondition: vold and keystore unlocked. * @@ -2579,8 +2518,8 @@ public class LockSettingsService extends ILockSettings.Stub { * This could also happen during an untrusted reset to clear password. * * 3. credentialhash == null and credential != null - * This is the untrusted credential reset, OR the user sets a new lockscreen password - * FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created + * The user sets a new lockscreen password FOR THE FIRST TIME on a SP-enabled device. + * New credential and new SID will be created */ @GuardedBy("mSpManager") @VisibleForTesting @@ -2905,8 +2844,7 @@ public class LockSettingsService extends ILockSettings.Stub { */ @GuardedBy("mSpManager") private boolean spBasedSetLockCredentialInternalLocked(LockscreenCredential credential, - LockscreenCredential savedCredential, int userId, - boolean allowUntrustedChange, boolean isLockTiedToParent) { + LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) { if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId); if (savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) { // get credential from keystore when managed profile has unified lock @@ -2927,50 +2865,24 @@ public class LockSettingsService extends ILockSettings.Stub { VerifyCredentialResponse response = authResult.gkResponse; AuthenticationToken auth = authResult.authToken; - // If existing credential is provided, the existing credential must match. - if (!savedCredential.isNone() && auth == null) { - Slog.w(TAG, "Failed to enroll: incorrect credential"); - return false; - } - boolean untrustedReset = false; - if (auth != null) { - onAuthTokenKnownForUser(userId, auth); - } else if (response == null) { - throw new IllegalStateException("Password change failed."); - } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) { - // We are performing an untrusted credential change, by DevicePolicyManager or other - // internal callers that don't provide the existing credential - Slog.w(TAG, "Untrusted credential change invoked"); - // Try to get a cached auth token, so we can keep SP unchanged. - auth = mSpCache.get(userId); - if (!allowUntrustedChange) { - throw new IllegalStateException("Untrusted credential change was invoked but it was" - + " not allowed. This is likely a bug. Auth token is null: " - + Boolean.toString(auth == null)); - } - untrustedReset = true; - } else /* responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ { - Slog.w(TAG, "Rate limit exceeded, so password was not changed."); - return false; - } - if (auth != null) { - if (untrustedReset) { - // Force change the current SID to mantain existing behaviour that an untrusted - // reset leads to a change of SID. If the untrusted reset is for clearing the - // current password, the nuking of the SID will be done in - // setLockCredentialWithAuthTokenLocked next - mSpManager.newSidForUser(getGateKeeperService(), auth, userId); + if (auth == null) { + if (response == null + || response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) { + Slog.w(TAG, "Failed to enroll: incorrect credential."); + return false; } - setLockCredentialWithAuthTokenLocked(credential, auth, userId); - mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId); - } else { - throw new IllegalStateException( - "Untrusted credential reset not possible without cached SP"); - // Could call initializeSyntheticPasswordLocked(null, credential, credentialType, - // requestedQuality, userId) instead if we still allow untrusted reset that changes - // synthetic password. That would invalidate existing escrow tokens though. + if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { + Slog.w(TAG, "Failed to enroll: rate limit exceeded."); + return false; + } + // Should not be reachable, but just in case. + throw new IllegalStateException("password change failed"); } + + onAuthTokenKnownForUser(userId, auth); + setLockCredentialWithAuthTokenLocked(credential, auth, userId); + mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId); sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent); return true; } @@ -3125,11 +3037,10 @@ public class LockSettingsService extends ILockSettings.Stub { + "verification."); return false; } + onAuthTokenKnownForUser(userId, result.authToken); long oldHandle = getSyntheticPasswordHandleLocked(userId); setLockCredentialWithAuthTokenLocked(credential, result.authToken, userId); mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId); - - onAuthTokenKnownForUser(userId, result.authToken); return true; } @@ -3248,8 +3159,6 @@ public class LockSettingsService extends ILockSettings.Stub { private class DeviceProvisionedObserver extends ContentObserver { private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor( Settings.Global.DEVICE_PROVISIONED); - private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor( - Settings.Secure.USER_SETUP_COMPLETE); private boolean mRegistered; @@ -3267,8 +3176,6 @@ public class LockSettingsService extends ILockSettings.Stub { reportDeviceSetupComplete(); clearFrpCredentialIfOwnerNotSecure(); } - } else if (mUserSetupCompleteUri.equals(uri)) { - tryRemoveUserFromSpCacheLater(userId); } } @@ -3320,8 +3227,6 @@ public class LockSettingsService extends ILockSettings.Stub { if (register) { mContext.getContentResolver().registerContentObserver(mDeviceProvisionedUri, false, this); - mContext.getContentResolver().registerContentObserver(mUserSetupCompleteUri, - false, this, UserHandle.USER_ALL); } else { mContext.getContentResolver().unregisterContentObserver(this); } diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index e9a8085950b0..c53647d053bc 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -136,8 +136,13 @@ public class SyntheticPasswordManager { "android-synthetic-password-personalization-context".getBytes(); static class AuthenticationResult { - public AuthenticationToken authToken; - public VerifyCredentialResponse gkResponse; + // Non-null if password/token passes verification, null otherwise + @Nullable public AuthenticationToken authToken; + // OK: password / token passes verification, user has a lockscreen + // null: user does not have a lockscreen (but password / token passes verification) + // ERROR: password / token fails verification + // RETRY: password / token verification is throttled at the moment. + @Nullable public VerifyCredentialResponse gkResponse; } /** diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index d0ad47d3d7a6..12afef2cf950 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -171,6 +171,7 @@ import android.os.IDeviceIdleController; import android.os.IInterface; import android.os.Looper; import android.os.Message; +import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; @@ -292,6 +293,9 @@ public class NotificationManagerService extends SystemService { public static final boolean ENABLE_CHILD_NOTIFICATIONS = SystemProperties.getBoolean("debug.child_notifs", true); + // pullStats report request: undecorated remote view stats + public static final int REPORT_REMOTE_VIEWS = 0x01; + static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean( "debug.notification.interruptiveness", false); @@ -4080,6 +4084,8 @@ public class NotificationManagerService extends SystemService { try { if (filter.stats) { dumpJson(pw, filter); + } else if (filter.rvStats) { + dumpRemoteViewStats(pw, filter); } else if (filter.proto) { dumpProto(fd, filter); } else if (filter.criticalPriority) { @@ -4556,6 +4562,49 @@ public class NotificationManagerService extends SystemService { new NotificationShellCmd(NotificationManagerService.this) .exec(this, in, out, err, args, callback, resultReceiver); } + + /** + * Get stats committed after startNs + * + * @param startNs Report stats committed after this time in nanoseconds. + * @param report Indicatess which section to include in the stats. + * @param doAgg Whether to aggregate the stats or keep them separated. + * @param out List of protos of individual commits or one representing the + * aggregate. + * @return the report time in nanoseconds, or 0 on error. + */ + @Override + public long pullStats(long startNs, int report, boolean doAgg, + List<ParcelFileDescriptor> out) { + checkCallerIsSystemOrShell(); + long startMs = TimeUnit.MILLISECONDS.convert(startNs, TimeUnit.NANOSECONDS); + + final long identity = Binder.clearCallingIdentity(); + try { + switch (report) { + case REPORT_REMOTE_VIEWS: + Slog.e(TAG, "pullStats REPORT_REMOTE_VIEWS from: " + + startMs + " wtih " + doAgg); + PulledStats stats = mUsageStats.remoteViewStats(startMs, doAgg); + if (stats != null) { + out.add(stats.toParcelFileDescriptor(report)); + Slog.e(TAG, "exiting pullStats with: " + out.size()); + long endNs = TimeUnit.NANOSECONDS + .convert(stats.endTimeMs(), TimeUnit.MILLISECONDS); + return endNs; + } + Slog.e(TAG, "null stats for: " + report); + } + } catch (IOException e) { + + Slog.e(TAG, "exiting pullStats: on error", e); + return 0; + } finally { + Binder.restoreCallingIdentity(identity); + } + Slog.e(TAG, "exiting pullStats: bad request"); + return 0; + } }; @VisibleForTesting @@ -4773,6 +4822,15 @@ public class NotificationManagerService extends SystemService { pw.println(dump); } + private void dumpRemoteViewStats(PrintWriter pw, @NonNull DumpFilter filter) { + PulledStats stats = mUsageStats.remoteViewStats(filter.since, true); + if (stats == null) { + pw.println("no remote view stats reported."); + return; + } + stats.dump(REPORT_REMOTE_VIEWS, pw, filter); + } + private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) { final ProtoOutputStream proto = new ProtoOutputStream(fd); synchronized (mNotificationLock) { @@ -9084,6 +9142,7 @@ public class NotificationManagerService extends SystemService { public boolean zen; public long since; public boolean stats; + public boolean rvStats; public boolean redact = true; public boolean proto = false; public boolean criticalPriority = false; @@ -9119,6 +9178,14 @@ public class NotificationManagerService extends SystemService { } else { filter.since = 0; } + } else if ("--remote-view-stats".equals(a)) { + filter.rvStats = true; + if (ai < args.length-1) { + ai++; + filter.since = Long.parseLong(args[ai]); + } else { + filter.since = 0; + } } else if (PRIORITY_ARG.equals(a)) { // Bugreport will call the service twice with priority arguments, first to dump // critical sections and then non critical ones. Set approriate filters diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java index fe3d0eb3e469..ac8d1a9a9ad4 100644 --- a/services/core/java/com/android/server/notification/NotificationUsageStats.java +++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java @@ -149,6 +149,7 @@ public class NotificationUsageStats { stats.numPostedByApp++; stats.updateInterarrivalEstimate(now); stats.countApiUse(notification); + stats.numUndecoratedRemoteViews += (isUndecoratedRemoteView(notification) ? 1 : 0); } releaseAggregatedStatsLocked(aggregatedStatsArray); if (ENABLE_SQLITE_LOG) { @@ -157,6 +158,13 @@ public class NotificationUsageStats { } /** + * Does this notification use RemoveViews without a platform decoration? + */ + protected static boolean isUndecoratedRemoteView(NotificationRecord notification) { + return (notification.getNotification().getNotificationStyle() == null); + } + + /** * Called when a notification has been updated. */ public synchronized void registerUpdatedByApp(NotificationRecord notification, @@ -337,6 +345,15 @@ public class NotificationUsageStats { return dump; } + public PulledStats remoteViewStats(long startMs, boolean aggregate) { + if (ENABLE_SQLITE_LOG) { + if (aggregate) { + return mSQLiteLog.remoteViewAggStats(startMs); + } + } + return null; + } + public synchronized void dump(PrintWriter pw, String indent, DumpFilter filter) { if (ENABLE_AGGREGATED_IN_MEMORY_STATS) { for (AggregatedStats as : mStats.values()) { @@ -414,6 +431,7 @@ public class NotificationUsageStats { public int numRateViolations; public int numAlertViolations; public int numQuotaViolations; + public int numUndecoratedRemoteViews; public long mLastAccessTime; public int numImagesRemoved; @@ -685,6 +703,8 @@ public class NotificationUsageStats { output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n"); output.append(indentPlusTwo).append(quietImportance.toString()).append("\n"); output.append(indentPlusTwo).append(finalImportance.toString()).append("\n"); + output.append(indentPlusTwo); + output.append("numUndecorateRVs=").append(numUndecoratedRemoteViews).append("\n"); output.append(indent).append("}"); return output.toString(); } @@ -1044,7 +1064,7 @@ public class NotificationUsageStats { private static final int MSG_DISMISS = 4; private static final String DB_NAME = "notification_log.db"; - private static final int DB_VERSION = 5; + private static final int DB_VERSION = 7; /** Age in ms after which events are pruned from the DB. */ private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L; // 1 week @@ -1077,6 +1097,7 @@ public class NotificationUsageStats { private static final String COL_FIRST_EXPANSIONTIME_MS = "first_expansion_time_ms"; private static final String COL_AIRTIME_EXPANDED_MS = "expansion_airtime_ms"; private static final String COL_EXPAND_COUNT = "expansion_count"; + private static final String COL_UNDECORATED = "undecorated"; private static final int EVENT_TYPE_POST = 1; @@ -1102,12 +1123,20 @@ public class NotificationUsageStats { "COUNT(*) AS cnt, " + "SUM(" + COL_MUTED + ") as muted, " + "SUM(" + COL_NOISY + ") as noisy, " + - "SUM(" + COL_DEMOTED + ") as demoted " + + "SUM(" + COL_DEMOTED + ") as demoted, " + + "SUM(" + COL_UNDECORATED + ") as undecorated " + "FROM " + TAB_LOG + " " + "WHERE " + COL_EVENT_TYPE + "=" + EVENT_TYPE_POST + " AND " + COL_EVENT_TIME + " > %d " + " GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG; + private static final String UNDECORATED_QUERY = "SELECT " + + COL_PKG + ", " + + "MAX(" + COL_EVENT_TIME + ") as max_time " + + "FROM " + TAB_LOG + " " + + "WHERE " + COL_UNDECORATED + "> 0 " + + " AND " + COL_EVENT_TIME + " > %d " + + "GROUP BY " + COL_PKG; public SQLiteLog(Context context) { HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log", @@ -1163,7 +1192,8 @@ public class NotificationUsageStats { COL_AIRTIME_MS + " INT," + COL_FIRST_EXPANSIONTIME_MS + " INT," + COL_AIRTIME_EXPANDED_MS + " INT," + - COL_EXPAND_COUNT + " INT" + + COL_EXPAND_COUNT + " INT," + + COL_UNDECORATED + " INT" + ")"); } @@ -1273,6 +1303,7 @@ public class NotificationUsageStats { } else { putPosttimeVisibility(r, cv); } + cv.put(COL_UNDECORATED, (isUndecoratedRemoteView(r) ? 1 : 0)); SQLiteDatabase db = mHelper.getWritableDatabase(); if (db.insert(TAB_LOG, null, cv) < 0) { Log.wtf(TAG, "Error while trying to insert values: " + cv); @@ -1353,5 +1384,22 @@ public class NotificationUsageStats { } return dump; } + + public PulledStats remoteViewAggStats(long startMs) { + PulledStats stats = new PulledStats(startMs); + SQLiteDatabase db = mHelper.getReadableDatabase(); + String q = String.format(UNDECORATED_QUERY, startMs); + Cursor cursor = db.rawQuery(q, null); + try { + for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { + String pkg = cursor.getString(0); + long maxTimeMs = cursor.getLong(1); + stats.addUndecoratedPackage(pkg, maxTimeMs); + } + } finally { + cursor.close(); + } + return stats; + } } } diff --git a/services/core/java/com/android/server/notification/PulledStats.java b/services/core/java/com/android/server/notification/PulledStats.java new file mode 100644 index 000000000000..ada890a10361 --- /dev/null +++ b/services/core/java/com/android/server/notification/PulledStats.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.notification; + +import static com.android.server.notification.NotificationManagerService.REPORT_REMOTE_VIEWS; + +import android.os.ParcelFileDescriptor; +import android.service.notification.NotificationRemoteViewsProto; +import android.service.notification.PackageRemoteViewInfoProto; +import android.util.Slog; +import android.util.proto.ProtoOutputStream; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +public class PulledStats { + static final String TAG = "PulledStats"; + + private final long mTimePeriodStartMs; + private long mTimePeriodEndMs; + private List<String> mUndecoratedPackageNames; + + public PulledStats(long startMs) { + mTimePeriodEndMs = mTimePeriodStartMs = startMs; + mUndecoratedPackageNames = new ArrayList<>(); + } + + ParcelFileDescriptor toParcelFileDescriptor(int report) + throws IOException { + final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); + switch(report) { + case REPORT_REMOTE_VIEWS: + Thread thr = new Thread("NotificationManager pulled metric output") { + public void run() { + try { + FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream( + fds[1]); + final ProtoOutputStream proto = new ProtoOutputStream(fout); + writeToProto(report, proto); + proto.flush(); + fout.close(); + } catch (IOException e) { + Slog.w(TAG, "Failure writing pipe", e); + } + } + }; + thr.start(); + break; + + default: + Slog.w(TAG, "Unknown pulled stats request: " + report); + break; + } + return fds[0]; + } + + /* + * @return the most recent timestamp in the report, as nanoseconds. + */ + public long endTimeMs() { + return mTimePeriodEndMs; + } + + public void dump(int report, PrintWriter pw, NotificationManagerService.DumpFilter filter) { + switch(report) { + case REPORT_REMOTE_VIEWS: + pw.print(" Packages with undecordated notifications ("); + pw.print(mTimePeriodStartMs); + pw.print(" - "); + pw.print(mTimePeriodEndMs); + pw.println("):"); + if (mUndecoratedPackageNames.size() == 0) { + pw.println(" none"); + } else { + for (String pkg : mUndecoratedPackageNames) { + if (!filter.filtered || pkg.equals(filter.pkgFilter)) { + pw.println(" " + pkg); + } + } + } + break; + + default: + pw.println("Unknown pulled stats request: " + report); + break; + } + } + + @VisibleForTesting + void writeToProto(int report, ProtoOutputStream proto) { + switch(report) { + case REPORT_REMOTE_VIEWS: + for (String pkg: mUndecoratedPackageNames) { + long token = proto.start(NotificationRemoteViewsProto.PACKAGE_REMOTE_VIEW_INFO); + proto.write(PackageRemoteViewInfoProto.PACKAGE_NAME, pkg); + proto.end(token); + } + break; + + default: + Slog.w(TAG, "Unknown pulled stats request: " + report); + break; + } + } + + public void addUndecoratedPackage(String packageName, long timestampMs) { + mUndecoratedPackageNames.add(packageName); + mTimePeriodEndMs = Math.max(mTimePeriodEndMs, timestampMs); + } +} diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java index e05511681ba8..ac3bf9ad5d8a 100644 --- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java +++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java @@ -26,6 +26,7 @@ import android.net.Uri; import android.os.Process; import android.os.RemoteException; import android.text.TextUtils; +import android.util.Pair; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; @@ -44,6 +45,38 @@ public class OverlayActorEnforcer { private final VerifyCallback mVerifyCallback; + /** + * @return nullable actor result with {@link ActorState} failure status + */ + static Pair<String, ActorState> getPackageNameForActor(String actorUriString, + Map<String, Map<String, String>> namedActors) { + if (namedActors.isEmpty()) { + return Pair.create(null, ActorState.NO_NAMED_ACTORS); + } + + Uri actorUri = Uri.parse(actorUriString); + + String actorScheme = actorUri.getScheme(); + List<String> actorPathSegments = actorUri.getPathSegments(); + if (!"overlay".equals(actorScheme) || CollectionUtils.size(actorPathSegments) != 1) { + return Pair.create(null, ActorState.INVALID_OVERLAYABLE_ACTOR_NAME); + } + + String actorNamespace = actorUri.getAuthority(); + Map<String, String> namespace = namedActors.get(actorNamespace); + if (namespace == null) { + return Pair.create(null, ActorState.MISSING_NAMESPACE); + } + + String actorName = actorPathSegments.get(0); + String packageName = namespace.get(actorName); + if (TextUtils.isEmpty(packageName)) { + return Pair.create(null, ActorState.MISSING_ACTOR_NAME); + } + + return Pair.create(packageName, ActorState.ALLOWED); + } + public OverlayActorEnforcer(@NonNull VerifyCallback verifyCallback) { mVerifyCallback = verifyCallback; } @@ -141,31 +174,14 @@ public class OverlayActorEnforcer { } } - Map<String, ? extends Map<String, String>> namedActors = mVerifyCallback.getNamedActors(); - if (namedActors.isEmpty()) { - return ActorState.NO_NAMED_ACTORS; - } - - Uri actorUri = Uri.parse(actor); - - String actorScheme = actorUri.getScheme(); - List<String> actorPathSegments = actorUri.getPathSegments(); - if (!"overlay".equals(actorScheme) || CollectionUtils.size(actorPathSegments) != 1) { - return ActorState.INVALID_OVERLAYABLE_ACTOR_NAME; - } - - String actorNamespace = actorUri.getAuthority(); - Map<String, String> namespace = namedActors.get(actorNamespace); - if (namespace == null) { - return ActorState.MISSING_NAMESPACE; - } - - String actorName = actorPathSegments.get(0); - String packageName = namespace.get(actorName); - if (TextUtils.isEmpty(packageName)) { - return ActorState.MISSING_ACTOR_NAME; + Map<String, Map<String, String>> namedActors = mVerifyCallback.getNamedActors(); + Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors); + ActorState actorUriState = actorUriPair.second; + if (actorUriState != ActorState.ALLOWED) { + return actorUriState; } + String packageName = actorUriPair.first; PackageInfo packageInfo = mVerifyCallback.getPackageInfo(packageName, userId); if (packageInfo == null) { return ActorState.MISSING_APP_INFO; @@ -192,7 +208,7 @@ public class OverlayActorEnforcer { * For easier logging/debugging, a set of all possible failure/success states when running * enforcement. */ - private enum ActorState { + enum ActorState { ALLOWED, INVALID_ACTOR, MISSING_NAMESPACE, @@ -244,7 +260,7 @@ public class OverlayActorEnforcer { * value maps actor name to package name */ @NonNull - Map<String, ? extends Map<String, String>> getNamedActors(); + Map<String, Map<String, String>> getNamedActors(); /** * @return true if the target package has declared an overlayable diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 63de61c9782f..f1947ac15645 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -533,13 +533,13 @@ public final class OverlayManagerService extends SystemService { private final IBinder mService = new IOverlayManager.Stub() { @Override - public Map<String, List<OverlayInfo>> getAllOverlays(int userId) throws RemoteException { + public Map<String, List<OverlayInfo>> getAllOverlays(final int userIdArg) { try { - traceBegin(TRACE_TAG_RRO, "OMS#getAllOverlays " + userId); - userId = handleIncomingUser(userId, "getAllOverlays"); + traceBegin(TRACE_TAG_RRO, "OMS#getAllOverlays " + userIdArg); + final int realUserId = handleIncomingUser(userIdArg, "getAllOverlays"); synchronized (mLock) { - return mImpl.getOverlaysForUser(userId); + return mImpl.getOverlaysForUser(realUserId); } } finally { traceEnd(TRACE_TAG_RRO); @@ -548,16 +548,17 @@ public final class OverlayManagerService extends SystemService { @Override public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName, - int userId) throws RemoteException { + final int userIdArg) { + if (targetPackageName == null) { + return Collections.emptyList(); + } + try { traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfosForTarget " + targetPackageName); - userId = handleIncomingUser(userId, "getOverlayInfosForTarget"); - if (targetPackageName == null) { - return Collections.emptyList(); - } + final int realUserId = handleIncomingUser(userIdArg, "getOverlayInfosForTarget"); synchronized (mLock) { - return mImpl.getOverlayInfosForTarget(targetPackageName, userId); + return mImpl.getOverlayInfosForTarget(targetPackageName, realUserId); } } finally { traceEnd(TRACE_TAG_RRO); @@ -566,16 +567,17 @@ public final class OverlayManagerService extends SystemService { @Override public OverlayInfo getOverlayInfo(@Nullable final String packageName, - int userId) throws RemoteException { + final int userIdArg) { + if (packageName == null) { + return null; + } + try { traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfo " + packageName); - userId = handleIncomingUser(userId, "getOverlayInfo"); - if (packageName == null) { - return null; - } + final int realUserId = handleIncomingUser(userIdArg, "getOverlayInfo"); synchronized (mLock) { - return mImpl.getOverlayInfo(packageName, userId); + return mImpl.getOverlayInfo(packageName, realUserId); } } finally { traceEnd(TRACE_TAG_RRO); @@ -584,19 +586,20 @@ public final class OverlayManagerService extends SystemService { @Override public boolean setEnabled(@Nullable final String packageName, final boolean enable, - int userId) throws RemoteException { + int userIdArg) { + if (packageName == null) { + return false; + } + try { traceBegin(TRACE_TAG_RRO, "OMS#setEnabled " + packageName + " " + enable); - enforceActor(packageName, "setEnabled", userId); - userId = handleIncomingUser(userId, "setEnabled"); - if (packageName == null) { - return false; - } + final int realUserId = handleIncomingUser(userIdArg, "setEnabled"); + enforceActor(packageName, "setEnabled", realUserId); final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - return mImpl.setEnabled(packageName, enable, userId); + return mImpl.setEnabled(packageName, enable, realUserId); } } finally { Binder.restoreCallingIdentity(ident); @@ -608,20 +611,21 @@ public final class OverlayManagerService extends SystemService { @Override public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable, - int userId) throws RemoteException { + int userIdArg) { + if (packageName == null || !enable) { + return false; + } + try { traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusive " + packageName + " " + enable); - enforceActor(packageName, "setEnabledExclusive", userId); - userId = handleIncomingUser(userId, "setEnabledExclusive"); - if (packageName == null || !enable) { - return false; - } + final int realUserId = handleIncomingUser(userIdArg, "setEnabledExclusive"); + enforceActor(packageName, "setEnabledExclusive", realUserId); final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { return mImpl.setEnabledExclusive(packageName, false /* withinCategory */, - userId); + realUserId); } } finally { Binder.restoreCallingIdentity(ident); @@ -632,21 +636,23 @@ public final class OverlayManagerService extends SystemService { } @Override - public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId) - throws RemoteException { + public boolean setEnabledExclusiveInCategory(@Nullable String packageName, + final int userIdArg) { + if (packageName == null) { + return false; + } + try { traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusiveInCategory " + packageName); - enforceActor(packageName, "setEnabledExclusiveInCategory", userId); - userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory"); - if (packageName == null) { - return false; - } + final int realUserId = handleIncomingUser(userIdArg, + "setEnabledExclusiveInCategory"); + enforceActor(packageName, "setEnabledExclusiveInCategory", realUserId); final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { return mImpl.setEnabledExclusive(packageName, true /* withinCategory */, - userId); + realUserId); } } finally { Binder.restoreCallingIdentity(ident); @@ -658,20 +664,21 @@ public final class OverlayManagerService extends SystemService { @Override public boolean setPriority(@Nullable final String packageName, - @Nullable final String parentPackageName, int userId) throws RemoteException { + @Nullable final String parentPackageName, final int userIdArg) { + if (packageName == null || parentPackageName == null) { + return false; + } + try { traceBegin(TRACE_TAG_RRO, "OMS#setPriority " + packageName + " " + parentPackageName); - enforceActor(packageName, "setPriority", userId); - userId = handleIncomingUser(userId, "setPriority"); - if (packageName == null || parentPackageName == null) { - return false; - } + final int realUserId = handleIncomingUser(userIdArg, "setPriority"); + enforceActor(packageName, "setPriority", realUserId); final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - return mImpl.setPriority(packageName, parentPackageName, userId); + return mImpl.setPriority(packageName, parentPackageName, realUserId); } } finally { Binder.restoreCallingIdentity(ident); @@ -682,20 +689,20 @@ public final class OverlayManagerService extends SystemService { } @Override - public boolean setHighestPriority(@Nullable final String packageName, int userId) - throws RemoteException { + public boolean setHighestPriority(@Nullable final String packageName, final int userIdArg) { + if (packageName == null) { + return false; + } + try { traceBegin(TRACE_TAG_RRO, "OMS#setHighestPriority " + packageName); - enforceActor(packageName, "setHighestPriority", userId); - userId = handleIncomingUser(userId, "setHighestPriority"); - if (packageName == null) { - return false; - } + final int realUserId = handleIncomingUser(userIdArg, "setHighestPriority"); + enforceActor(packageName, "setHighestPriority", realUserId); final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - return mImpl.setHighestPriority(packageName, userId); + return mImpl.setHighestPriority(packageName, realUserId); } } finally { Binder.restoreCallingIdentity(ident); @@ -706,20 +713,20 @@ public final class OverlayManagerService extends SystemService { } @Override - public boolean setLowestPriority(@Nullable final String packageName, int userId) - throws RemoteException { + public boolean setLowestPriority(@Nullable final String packageName, final int userIdArg) { + if (packageName == null) { + return false; + } + try { traceBegin(TRACE_TAG_RRO, "OMS#setLowestPriority " + packageName); - enforceActor(packageName, "setLowestPriority", userId); - userId = handleIncomingUser(userId, "setLowestPriority"); - if (packageName == null) { - return false; - } + final int realUserId = handleIncomingUser(userIdArg, "setLowestPriority"); + enforceActor(packageName, "setLowestPriority", realUserId); final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - return mImpl.setLowestPriority(packageName, userId); + return mImpl.setLowestPriority(packageName, realUserId); } } finally { Binder.restoreCallingIdentity(ident); @@ -730,7 +737,7 @@ public final class OverlayManagerService extends SystemService { } @Override - public String[] getDefaultOverlayPackages() throws RemoteException { + public String[] getDefaultOverlayPackages() { try { traceBegin(TRACE_TAG_RRO, "OMS#getDefaultOverlayPackages"); getContext().enforceCallingOrSelfPermission( @@ -750,18 +757,17 @@ public final class OverlayManagerService extends SystemService { } @Override - public void invalidateCachesForOverlay(@Nullable String packageName, int userId) - throws RemoteException { + public void invalidateCachesForOverlay(@Nullable String packageName, final int userIdArg) { if (packageName == null) { return; } - enforceActor(packageName, "invalidateCachesForOverlay", userId); - userId = handleIncomingUser(userId, "invalidateCachesForOverlay"); + final int realUserId = handleIncomingUser(userIdArg, "invalidateCachesForOverlay"); + enforceActor(packageName, "invalidateCachesForOverlay", realUserId); final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - mImpl.removeIdmapForOverlay(packageName, userId); + mImpl.removeIdmapForOverlay(packageName, realUserId); } } finally { Binder.restoreCallingIdentity(ident); @@ -876,11 +882,16 @@ public final class OverlayManagerService extends SystemService { getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, message); } - private void enforceActor(String packageName, String methodName, int userId) + private void enforceActor(String packageName, String methodName, int realUserId) throws SecurityException { - OverlayInfo overlayInfo = mImpl.getOverlayInfo(packageName, userId); + OverlayInfo overlayInfo = mImpl.getOverlayInfo(packageName, realUserId); + if (overlayInfo == null) { + throw new IllegalArgumentException("Unable to retrieve overlay information for " + + packageName); + } + int callingUid = Binder.getCallingUid(); - mActorEnforcer.enforceActor(overlayInfo, methodName, callingUid, userId); + mActorEnforcer.enforceActor(overlayInfo, methodName, callingUid, realUserId); } }; @@ -1062,8 +1073,6 @@ public final class OverlayManagerService extends SystemService { mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); } - // TODO(b/143096091): Remove PackageInfo cache so that PackageManager is always queried - // to enforce visibility/other permission checks public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId, final boolean useCache) { if (useCache) { @@ -1086,18 +1095,12 @@ public final class OverlayManagerService extends SystemService { @Override public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) { - // TODO(b/143096091): Remove clearing calling ID - long callingIdentity = Binder.clearCallingIdentity(); - try { - return getPackageInfo(packageName, userId, true); - } finally { - Binder.restoreCallingIdentity(callingIdentity); - } + return getPackageInfo(packageName, userId, true); } @NonNull @Override - public Map<String, ? extends Map<String, String>> getNamedActors() { + public Map<String, Map<String, String>> getNamedActors() { return SystemConfig.getInstance().getNamedActors(); } @@ -1125,57 +1128,45 @@ public final class OverlayManagerService extends SystemService { public OverlayableInfo getOverlayableForTarget(@NonNull String packageName, @Nullable String targetOverlayableName, int userId) throws IOException { - // TODO(b/143096091): Remove clearing calling ID - long callingIdentity = Binder.clearCallingIdentity(); - try { - PackageInfo packageInfo = getPackageInfo(packageName, userId); - if (packageInfo == null) { - throw new IOException("Unable to get target package"); - } + PackageInfo packageInfo = getPackageInfo(packageName, userId); + if (packageInfo == null) { + throw new IOException("Unable to get target package"); + } - String baseCodePath = packageInfo.applicationInfo.getBaseCodePath(); + String baseCodePath = packageInfo.applicationInfo.getBaseCodePath(); - ApkAssets apkAssets = null; - try { - apkAssets = ApkAssets.loadFromPath(baseCodePath); - return apkAssets.getOverlayableInfo(targetOverlayableName); - } finally { - if (apkAssets != null) { - try { - apkAssets.close(); - } catch (Throwable ignored) { - } + ApkAssets apkAssets = null; + try { + apkAssets = ApkAssets.loadFromPath(baseCodePath); + return apkAssets.getOverlayableInfo(targetOverlayableName); + } finally { + if (apkAssets != null) { + try { + apkAssets.close(); + } catch (Throwable ignored) { } } - } finally { - Binder.restoreCallingIdentity(callingIdentity); } } @Override public boolean doesTargetDefineOverlayable(String targetPackageName, int userId) throws RemoteException, IOException { - // TODO(b/143096091): Remove clearing calling ID - long callingIdentity = Binder.clearCallingIdentity(); - try { - PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, 0, - userId); - String baseCodePath = packageInfo.applicationInfo.getBaseCodePath(); + PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, 0, + userId); + String baseCodePath = packageInfo.applicationInfo.getBaseCodePath(); - ApkAssets apkAssets = null; - try { - apkAssets = ApkAssets.loadFromPath(baseCodePath); - return apkAssets.definesOverlayable(); - } finally { - if (apkAssets != null) { - try { - apkAssets.close(); - } catch (Throwable ignored) { - } + ApkAssets apkAssets = null; + try { + apkAssets = ApkAssets.loadFromPath(baseCodePath); + return apkAssets.definesOverlayable(); + } finally { + if (apkAssets != null) { + try { + apkAssets.close(); + } catch (Throwable ignored) { } } - } finally { - Binder.restoreCallingIdentity(callingIdentity); } } @@ -1218,16 +1209,10 @@ public final class OverlayManagerService extends SystemService { @Nullable @Override public String[] getPackagesForUid(int uid) { - // TODO(b/143096091): Remove clearing calling ID - long callingIdentity = Binder.clearCallingIdentity(); try { - try { - return mPackageManager.getPackagesForUid(uid); - } catch (RemoteException ignored) { - return null; - } - } finally { - Binder.restoreCallingIdentity(callingIdentity); + return mPackageManager.getPackagesForUid(uid); + } catch (RemoteException ignored) { + return null; } } diff --git a/services/core/java/com/android/server/om/OverlayReferenceMapper.java b/services/core/java/com/android/server/om/OverlayReferenceMapper.java new file mode 100644 index 000000000000..8bea119f3490 --- /dev/null +++ b/services/core/java/com/android/server/om/OverlayReferenceMapper.java @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.om; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.parsing.AndroidPackage; +import android.text.TextUtils; +import android.util.ArraySet; +import android.util.Pair; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.CollectionUtils; +import com.android.server.SystemConfig; +import com.android.server.pm.PackageSetting; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * Track visibility of a targets and overlays to actors. + * + * 4 cases to handle: + * <ol> + * <li>Target adds/changes an overlayable to add a reference to an actor + * <ul> + * <li>Must expose target to actor</li> + * <li>Must expose any overlays that pointed to that overlayable name to the actor</li> + * </ul> + * </li> + * <li>Target removes/changes an overlayable to remove a reference to an actor + * <ul> + * <li>If this target has no other overlayables referencing the actor, hide the + * target</li> + * <li>For all overlays targeting this overlayable, if the overlay is only visible to + * the actor through this overlayable, hide the overlay</li> + * </ul> + * </li> + * <li>Overlay adds/changes an overlay tag to add a reference to an overlayable name + * <ul> + * <li>Expose this overlay to the actor defined by the target overlayable</li> + * </ul> + * </li> + * <li>Overlay removes/changes an overlay tag to remove a reference to an overlayable name + * <ul> + * <li>If this overlay is only visible to an actor through this overlayable name's + * target's actor</li> + * </ul> + * </li> + * </ol> + * + * In this class, the names "actor", "target", and "overlay" all refer to the ID representations. + * All other use cases are named appropriate. "actor" is actor name, "target" is target package + * name, and "overlay" is overlay package name. + */ +public class OverlayReferenceMapper { + + private final Object mLock = new Object(); + + /** + * Keys are actors, values are maps which map target to a set of overlays targeting it. + * The presence of a target in the value map means the actor and targets are connected, even + * if the corresponding target's set is empty. + * See class comment for specific types. + */ + @GuardedBy("mLock") + private final Map<String, Map<String, Set<String>>> mActorToTargetToOverlays = new HashMap<>(); + + /** + * Keys are actor package names, values are generic package names the actor should be able + * to see. + */ + @GuardedBy("mLock") + private final Map<String, Set<String>> mActorPkgToPkgs = new HashMap<>(); + + @GuardedBy("mLock") + private boolean mDeferRebuild; + + @NonNull + private final Provider mProvider; + + /** + * @param deferRebuild whether or not to defer rebuild calls on add/remove until first get call; + * useful during boot when multiple packages are added in rapid succession + * and queries in-between are not expected + */ + public OverlayReferenceMapper(boolean deferRebuild, @Nullable Provider provider) { + this.mDeferRebuild = deferRebuild; + this.mProvider = provider != null ? provider : new Provider() { + @Nullable + @Override + public String getActorPkg(String actor) { + Map<String, Map<String, String>> namedActors = SystemConfig.getInstance() + .getNamedActors(); + + Pair<String, OverlayActorEnforcer.ActorState> actorPair = + OverlayActorEnforcer.getPackageNameForActor(actor, namedActors); + return actorPair.first; + } + + @NonNull + @Override + public Map<String, Set<String>> getTargetToOverlayables(@NonNull AndroidPackage pkg) { + String target = pkg.getOverlayTarget(); + if (TextUtils.isEmpty(target)) { + return Collections.emptyMap(); + } + + String overlayable = pkg.getOverlayTargetName(); + Map<String, Set<String>> targetToOverlayables = new HashMap<>(); + Set<String> overlayables = new HashSet<>(); + overlayables.add(overlayable); + targetToOverlayables.put(target, overlayables); + return targetToOverlayables; + } + }; + } + + /** + * @return mapping of actor package to a set of packages it can view + */ + @NonNull + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + public Map<String, Set<String>> getActorPkgToPkgs() { + return mActorPkgToPkgs; + } + + public boolean isValidActor(@NonNull String targetName, @NonNull String actorPackageName) { + synchronized (mLock) { + assertMapBuilt(); + Set<String> validSet = mActorPkgToPkgs.get(actorPackageName); + return validSet != null && validSet.contains(targetName); + } + } + + /** + * Add a package to be considered for visibility. Currently supports adding as a target and/or + * an overlay. Adding an actor is not supported. Those are configured as part of + * {@link SystemConfig#getNamedActors()}. + * + * @param pkg the package to add + * @param otherPkgs map of other packages to consider, excluding {@param pkg} + */ + public void addPkg(AndroidPackage pkg, Map<String, AndroidPackage> otherPkgs) { + synchronized (mLock) { + if (!pkg.getOverlayables().isEmpty()) { + addTarget(pkg, otherPkgs); + } + + // TODO(b/135203078): Replace with isOverlay boolean flag check; fix test mocks + if (!mProvider.getTargetToOverlayables(pkg).isEmpty()) { + addOverlay(pkg, otherPkgs); + } + + if (!mDeferRebuild) { + rebuild(); + } + } + } + + /** + * Removes a package to be considered for visibility. Currently supports removing as a target + * and/or an overlay. Removing an actor is not supported. Those are staticly configured as part + * of {@link SystemConfig#getNamedActors()}. + * + * @param pkgName name to remove, as was added through {@link #addPkg(AndroidPackage, Map)} + */ + public void removePkg(String pkgName) { + synchronized (mLock) { + removeTarget(pkgName); + removeOverlay(pkgName); + + if (!mDeferRebuild) { + rebuild(); + } + } + } + + private void removeTarget(String target) { + synchronized (mLock) { + Iterator<Map<String, Set<String>>> iterator = + mActorToTargetToOverlays.values().iterator(); + while (iterator.hasNext()) { + Map<String, Set<String>> next = iterator.next(); + next.remove(target); + if (next.isEmpty()) { + iterator.remove(); + } + } + } + } + + /** + * Associate an actor with an association of a new target to overlays for that target. + * + * If a target overlays itself, it will not be associated with itself, as only one half of the + * relationship needs to exist for visibility purposes. + */ + private void addTarget(AndroidPackage targetPkg, Map<String, AndroidPackage> otherPkgs) { + synchronized (mLock) { + String target = targetPkg.getPackageName(); + removeTarget(target); + + Map<String, String> overlayablesToActors = targetPkg.getOverlayables(); + for (String overlayable : overlayablesToActors.keySet()) { + String actor = overlayablesToActors.get(overlayable); + addTargetToMap(actor, target); + + for (AndroidPackage overlayPkg : otherPkgs.values()) { + Map<String, Set<String>> targetToOverlayables = + mProvider.getTargetToOverlayables(overlayPkg); + Set<String> overlayables = targetToOverlayables.get(target); + if (CollectionUtils.isEmpty(overlayables)) { + continue; + } + + if (overlayables.contains(overlayable)) { + addOverlayToMap(actor, target, overlayPkg.getPackageName()); + } + } + } + } + } + + private void removeOverlay(String overlay) { + synchronized (mLock) { + for (Map<String, Set<String>> targetToOverlays : mActorToTargetToOverlays.values()) { + for (Set<String> overlays : targetToOverlays.values()) { + overlays.remove(overlay); + } + } + } + } + + /** + * Associate an actor with an association of targets to overlays for a new overlay. + * + * If an overlay targets itself, it will not be associated with itself, as only one half of the + * relationship needs to exist for visibility purposes. + */ + private void addOverlay(AndroidPackage overlayPkg, Map<String, AndroidPackage> otherPkgs) { + synchronized (mLock) { + String overlay = overlayPkg.getPackageName(); + removeOverlay(overlay); + + Map<String, Set<String>> targetToOverlayables = + mProvider.getTargetToOverlayables(overlayPkg); + for (Map.Entry<String, Set<String>> entry : targetToOverlayables.entrySet()) { + String target = entry.getKey(); + Set<String> overlayables = entry.getValue(); + AndroidPackage targetPkg = otherPkgs.get(target); + if (targetPkg == null) { + continue; + } + + String targetPkgName = targetPkg.getPackageName(); + Map<String, String> overlayableToActor = targetPkg.getOverlayables(); + for (String overlayable : overlayables) { + String actor = overlayableToActor.get(overlayable); + if (TextUtils.isEmpty(actor)) { + continue; + } + addOverlayToMap(actor, targetPkgName, overlay); + } + } + } + } + + public void rebuildIfDeferred() { + synchronized (mLock) { + if (mDeferRebuild) { + rebuild(); + mDeferRebuild = false; + } + } + } + + private void assertMapBuilt() { + if (mDeferRebuild) { + throw new IllegalStateException("The actor map must be built by calling " + + "rebuildIfDeferred before it is queried"); + } + } + + private void rebuild() { + synchronized (mLock) { + mActorPkgToPkgs.clear(); + for (String actor : mActorToTargetToOverlays.keySet()) { + String actorPkg = mProvider.getActorPkg(actor); + if (TextUtils.isEmpty(actorPkg)) { + continue; + } + + Map<String, Set<String>> targetToOverlays = mActorToTargetToOverlays.get(actor); + Set<String> pkgs = new HashSet<>(); + + for (String target : targetToOverlays.keySet()) { + Set<String> overlays = targetToOverlays.get(target); + pkgs.add(target); + pkgs.addAll(overlays); + } + + mActorPkgToPkgs.put(actorPkg, pkgs); + } + } + } + + private void addTargetToMap(String actor, String target) { + Map<String, Set<String>> targetToOverlays = mActorToTargetToOverlays.get(actor); + if (targetToOverlays == null) { + targetToOverlays = new HashMap<>(); + mActorToTargetToOverlays.put(actor, targetToOverlays); + } + + Set<String> overlays = targetToOverlays.get(target); + if (overlays == null) { + overlays = new HashSet<>(); + targetToOverlays.put(target, overlays); + } + } + + private void addOverlayToMap(String actor, String target, String overlay) { + synchronized (mLock) { + Map<String, Set<String>> targetToOverlays = mActorToTargetToOverlays.get(actor); + if (targetToOverlays == null) { + targetToOverlays = new HashMap<>(); + mActorToTargetToOverlays.put(actor, targetToOverlays); + } + + Set<String> overlays = targetToOverlays.get(target); + if (overlays == null) { + overlays = new HashSet<>(); + targetToOverlays.put(target, overlays); + } + + overlays.add(overlay); + } + } + + public interface Provider { + + /** + * Given the actor string from an overlayable definition, return the actor's package name. + */ + @Nullable + String getActorPkg(String actor); + + /** + * Mock response of multiple overlay tags. + * + * TODO(b/119899133): Replace with actual implementation; fix OverlayReferenceMapperTests + */ + @NonNull + Map<String, Set<String>> getTargetToOverlayables(@NonNull AndroidPackage pkg); + } +} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java b/services/core/java/com/android/server/package-info.java index 10d0551a3a6f..a783e8d61a32 100644 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java +++ b/services/core/java/com/android/server/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,13 +12,6 @@ * 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.frameworks.coretests; - -import android.app.Activity; - -public class TestActivity extends Activity { - -} +@android.annotation.Hide +package com.android.server; diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index 1222d9a29baf..2b4b409f329a 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -36,6 +36,7 @@ import android.os.Environment; import android.os.RemoteException; import android.os.ServiceManager; import android.sysprop.ApexProperties; +import android.util.Singleton; import android.util.Slog; import com.android.internal.annotations.GuardedBy; @@ -65,22 +66,31 @@ abstract class ApexManager { static final int MATCH_ACTIVE_PACKAGE = 1 << 0; static final int MATCH_FACTORY_PACKAGE = 1 << 1; + private static final Singleton<ApexManager> sApexManagerSingleton = + new Singleton<ApexManager>() { + @Override + protected ApexManager create() { + if (ApexProperties.updatable().orElse(false)) { + try { + return new ApexManagerImpl(IApexService.Stub.asInterface( + ServiceManager.getServiceOrThrow("apexservice"))); + } catch (ServiceManager.ServiceNotFoundException e) { + throw new IllegalStateException( + "Required service apexservice not available"); + } + } else { + return new ApexManagerFlattenedApex(); + } + } + }; + /** * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerFlattenedApex} * depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()} * evaluates to {@code true}. */ - static ApexManager create(Context systemContext) { - if (ApexProperties.updatable().orElse(false)) { - try { - return new ApexManagerImpl(systemContext, IApexService.Stub.asInterface( - ServiceManager.getServiceOrThrow("apexservice"))); - } catch (ServiceManager.ServiceNotFoundException e) { - throw new IllegalStateException("Required service apexservice not available"); - } - } else { - return new ApexManagerFlattenedApex(); - } + static ApexManager getInstance() { + return sApexManagerSingleton.get(); } /** @@ -101,7 +111,7 @@ abstract class ApexManager { */ abstract List<ActiveApexInfo> getActiveApexInfos(); - abstract void systemReady(); + abstract void systemReady(Context context); /** * Retrieves information about an APEX package. @@ -248,7 +258,6 @@ abstract class ApexManager { @VisibleForTesting static class ApexManagerImpl extends ApexManager { private final IApexService mApexService; - private final Context mContext; private final Object mLock = new Object(); /** * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code @@ -260,8 +269,7 @@ abstract class ApexManager { @GuardedBy("mLock") private List<PackageInfo> mAllPackagesCache; - ApexManagerImpl(Context context, IApexService apexService) { - mContext = context; + ApexManagerImpl(IApexService apexService) { mApexService = apexService; } @@ -302,14 +310,14 @@ abstract class ApexManager { } @Override - void systemReady() { - mContext.registerReceiver(new BroadcastReceiver() { + void systemReady(Context context) { + context.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Post populateAllPackagesCacheIfNeeded to a background thread, since it's // expensive to run it in broadcast handler thread. BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded()); - mContext.unregisterReceiver(this); + context.unregisterReceiver(this); } }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); } @@ -643,7 +651,7 @@ abstract class ApexManager { } @Override - void systemReady() { + void systemReady(Context context) { // No-op } diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 14ef2d3a38e1..c4bcf809a67d 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -16,8 +16,6 @@ package com.android.server.pm; -import static android.content.pm.PackageParser.Component; -import static android.content.pm.PackageParser.IntentInfo; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; @@ -26,8 +24,13 @@ import android.annotation.Nullable; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; -import android.content.pm.ProviderInfo; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; +import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; import android.net.Uri; import android.os.Process; import android.os.Trace; @@ -44,9 +47,10 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.server.FgThread; +import com.android.server.om.OverlayReferenceMapper; import java.io.PrintWriter; -import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -102,11 +106,16 @@ public class AppsFilter { private final FeatureConfig mFeatureConfig; + private final OverlayReferenceMapper mOverlayReferenceMapper; + AppsFilter(FeatureConfig featureConfig, String[] forceQueryableWhitelist, - boolean systemAppsQueryable) { + boolean systemAppsQueryable, + @Nullable OverlayReferenceMapper.Provider overlayProvider) { mFeatureConfig = featureConfig; mForceQueryableByDevicePackageNames = forceQueryableWhitelist; mSystemAppsQueryable = systemAppsQueryable; + mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/, + overlayProvider); } public interface FeatureConfig { @@ -117,7 +126,7 @@ public class AppsFilter { boolean isGloballyEnabled(); /** @return true if the feature is enabled for the given package. */ - boolean packageIsEnabled(PackageParser.Package pkg); + boolean packageIsEnabled(AndroidPackage pkg); } private static class FeatureConfigImpl implements FeatureConfig { @@ -156,11 +165,12 @@ public class AppsFilter { } @Override - public boolean packageIsEnabled(PackageParser.Package pkg) { + public boolean packageIsEnabled(AndroidPackage pkg) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "packageIsEnabled"); try { + // TODO(b/135203078): Do not use toAppInfo return mInjector.getCompatibility().isChangeEnabled( - PackageManager.FILTER_APPLICATION_QUERY, pkg.applicationInfo); + PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState()); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } @@ -185,16 +195,16 @@ public class AppsFilter { } } return new AppsFilter(featureConfig, forcedQueryablePackageNames, - forceSystemAppsQueryable); + forceSystemAppsQueryable, null); } /** Returns true if the querying package may query for the potential target package */ - private static boolean canQueryViaIntent(PackageParser.Package querying, - PackageParser.Package potentialTarget) { - if (querying.mQueriesIntents == null) { + private static boolean canQueryViaIntent(AndroidPackage querying, + AndroidPackage potentialTarget) { + if (querying.getQueriesIntents() == null) { return false; } - for (Intent intent : querying.mQueriesIntents) { + for (Intent intent : querying.getQueriesIntents()) { if (matches(intent, potentialTarget)) { return true; } @@ -202,41 +212,40 @@ public class AppsFilter { return false; } - private static boolean matches(Intent intent, PackageParser.Package potentialTarget) { - for (int p = potentialTarget.providers.size() - 1; p >= 0; p--) { - PackageParser.Provider provider = potentialTarget.providers.get(p); - if (!provider.info.exported) { + private static boolean matches(Intent intent, AndroidPackage potentialTarget) { + for (int p = ArrayUtils.size(potentialTarget.getProviders()) - 1; p >= 0; p--) { + ParsedProvider provider = potentialTarget.getProviders().get(p); + if (!provider.isExported()) { continue; } - final ProviderInfo providerInfo = provider.info; final Uri data = intent.getData(); if ("content".equalsIgnoreCase(intent.getScheme()) && data != null - && Objects.equals(providerInfo.authority, data.getAuthority())) { + && Objects.equals(provider.getAuthority(), data.getAuthority())) { return true; } } - for (int s = potentialTarget.services.size() - 1; s >= 0; s--) { - PackageParser.Service service = potentialTarget.services.get(s); - if (!service.info.exported) { + for (int s = ArrayUtils.size(potentialTarget.getServices()) - 1; s >= 0; s--) { + ParsedService service = potentialTarget.getServices().get(s); + if (!service.exported) { continue; } if (matchesAnyFilter(intent, service)) { return true; } } - for (int a = potentialTarget.activities.size() - 1; a >= 0; a--) { - PackageParser.Activity activity = potentialTarget.activities.get(a); - if (!activity.info.exported) { + for (int a = ArrayUtils.size(potentialTarget.getActivities()) - 1; a >= 0; a--) { + ParsedActivity activity = potentialTarget.getActivities().get(a); + if (!activity.exported) { continue; } if (matchesAnyFilter(intent, activity)) { return true; } } - for (int r = potentialTarget.receivers.size() - 1; r >= 0; r--) { - PackageParser.Activity receiver = potentialTarget.receivers.get(r); - if (!receiver.info.exported) { + for (int r = ArrayUtils.size(potentialTarget.getReceivers()) - 1; r >= 0; r--) { + ParsedActivity receiver = potentialTarget.getReceivers().get(r); + if (!receiver.exported) { continue; } if (matchesAnyFilter(intent, receiver)) { @@ -247,9 +256,9 @@ public class AppsFilter { } private static boolean matchesAnyFilter( - Intent intent, Component<? extends IntentInfo> component) { - ArrayList<? extends IntentInfo> intents = component.intents; - for (int i = intents.size() - 1; i >= 0; i--) { + Intent intent, ParsedComponent<? extends ParsedIntentInfo> component) { + List<? extends ParsedIntentInfo> intents = component.intents; + for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) { IntentFilter intentFilter = intents.get(i); if (intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(), intent.getData(), intent.getCategories(), "AppsFilter") > 0) { @@ -275,6 +284,7 @@ public class AppsFilter { public void onSystemReady() { mFeatureConfig.onSystemReady(); + mOverlayReferenceMapper.rebuildIfDeferred(); } /** @@ -287,7 +297,7 @@ public class AppsFilter { ArrayMap<String, PackageSetting> existingSettings) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); try { - final PackageParser.Package newPkg = newPkgSetting.pkg; + final AndroidPackage newPkg = newPkgSetting.pkg; if (newPkg == null) { // nothing to add return; @@ -296,10 +306,10 @@ public class AppsFilter { final boolean newIsForceQueryable = mForceQueryable.contains(newPkgSetting.appId) /* shared user that is already force queryable */ - || newPkg.mForceQueryable + || newPkg.isForceQueryable() || (newPkgSetting.isSystem() && (mSystemAppsQueryable || ArrayUtils.contains(mForceQueryableByDevicePackageNames, - newPkg.packageName))); + newPkg.getPackageName()))); if (newIsForceQueryable) { mForceQueryable.add(newPkgSetting.appId); } @@ -309,14 +319,14 @@ public class AppsFilter { if (existingSetting.appId == newPkgSetting.appId || existingSetting.pkg == null) { continue; } - final PackageParser.Package existingPkg = existingSetting.pkg; + final AndroidPackage existingPkg = existingSetting.pkg; // let's evaluate the ability of already added packages to see this new package if (!newIsForceQueryable) { if (canQueryViaIntent(existingPkg, newPkg)) { mQueriesViaIntent.add(existingSetting.appId, newPkgSetting.appId); } - if (existingPkg.mQueriesPackages != null - && existingPkg.mQueriesPackages.contains(newPkg.packageName)) { + if (existingPkg.getQueriesPackages() != null + && existingPkg.getQueriesPackages().contains(newPkg.getPackageName())) { mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); } } @@ -325,12 +335,22 @@ public class AppsFilter { if (canQueryViaIntent(newPkg, existingPkg)) { mQueriesViaIntent.add(newPkgSetting.appId, existingSetting.appId); } - if (newPkg.mQueriesPackages != null - && newPkg.mQueriesPackages.contains(existingPkg.packageName)) { + if (newPkg.getQueriesPackages() != null + && newPkg.getQueriesPackages().contains(existingPkg.getPackageName())) { mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId); } } } + + int existingSize = existingSettings.size(); + ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize); + for (int index = 0; index < existingSize; index++) { + PackageSetting pkgSetting = existingSettings.valueAt(index); + if (pkgSetting.pkg != null) { + existingPkgs.put(pkgSetting.name, pkgSetting.pkg); + } + } + mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } @@ -374,6 +394,8 @@ public class AppsFilter { addPackage(setting.sharedUser.packages.valueAt(i), existingSettings); } } + + mOverlayReferenceMapper.removePkg(setting.name); } /** @@ -390,8 +412,7 @@ public class AppsFilter { PackageSetting targetPkgSetting, int userId) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication"); try { - if (!shouldFilterApplicationInternal(callingUid, callingSetting, - targetPkgSetting, + if (!shouldFilterApplicationInternal(callingUid, callingSetting, targetPkgSetting, userId)) { return false; } @@ -405,8 +426,8 @@ public class AppsFilter { } } - private boolean shouldFilterApplicationInternal(int callingUid, - SettingBase callingSetting, PackageSetting targetPkgSetting, int userId) { + private boolean shouldFilterApplicationInternal(int callingUid, SettingBase callingSetting, + PackageSetting targetPkgSetting, int userId) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplicationInternal"); try { final boolean featureEnabled = mFeatureConfig.isGloballyEnabled(); @@ -456,14 +477,14 @@ public class AppsFilter { // This package isn't technically installed and won't be written to settings, so we can // treat it as filtered until it's available again. - final PackageParser.Package targetPkg = targetPkgSetting.pkg; + final AndroidPackage targetPkg = targetPkgSetting.pkg; if (targetPkg == null) { if (DEBUG_LOGGING) { Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null"); } return true; } - final String targetName = targetPkg.packageName; + final String targetName = targetPkg.getPackageName(); final int callingAppId; if (callingPkgSetting != null) { callingAppId = callingPkgSetting.appId; @@ -523,6 +544,29 @@ public class AppsFilter { } } } + + if (callingSharedPkgSettings != null) { + int size = callingSharedPkgSettings.size(); + for (int index = 0; index < size; index++) { + PackageSetting pkgSetting = callingSharedPkgSettings.valueAt(index); + if (mOverlayReferenceMapper.isValidActor(targetName, pkgSetting.name)) { + if (DEBUG_LOGGING) { + log(callingPkgSetting, targetPkgSetting, + "matches shared user of package that acts on target of " + + "overlay"); + } + return false; + } + } + } else { + if (mOverlayReferenceMapper.isValidActor(targetName, callingPkgSetting.name)) { + if (DEBUG_LOGGING) { + log(callingPkgSetting, targetPkgSetting, "acts on target of overlay"); + } + return false; + } + } + return true; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); @@ -532,9 +576,10 @@ public class AppsFilter { private static boolean callingPkgInstruments(PackageSetting callingPkgSetting, PackageSetting targetPkgSetting, String targetName) { - final ArrayList<PackageParser.Instrumentation> inst = callingPkgSetting.pkg.instrumentation; - for (int i = inst.size() - 1; i >= 0; i--) { - if (inst.get(i).info.targetPackage == targetName) { + final List<ComponentParseUtils.ParsedInstrumentation> inst = + callingPkgSetting.pkg.getInstrumentations(); + for (int i = ArrayUtils.size(inst) - 1; i >= 0; i--) { + if (Objects.equals(inst.get(i).getTargetPackage(), targetName)) { if (DEBUG_LOGGING) { log(callingPkgSetting, targetPkgSetting, "instrumentation"); } diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java index b1eb7e79bc1b..f2a2e65f733b 100644 --- a/services/core/java/com/android/server/pm/ComponentResolver.java +++ b/services/core/java/com/android/server/pm/ComponentResolver.java @@ -21,7 +21,6 @@ import static android.content.pm.PackageManagerInternal.PACKAGE_SETUP_WIZARD; import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE; -import static com.android.server.pm.PackageManagerService.fixProcessName; import android.annotation.Nullable; import android.content.ComponentName; @@ -33,13 +32,18 @@ import android.content.pm.AuxiliaryResolveInfo; import android.content.pm.InstantAppResolveInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; -import android.content.pm.PackageParser; -import android.content.pm.PackageParser.ActivityIntentInfo; -import android.content.pm.PackageParser.ServiceIntentInfo; import android.content.pm.PackageUserState; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedProviderIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.content.pm.parsing.ComponentParseUtils.ParsedServiceIntentInfo; +import android.content.pm.parsing.PackageInfoUtils; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; @@ -55,11 +59,14 @@ import com.android.server.IntentResolver; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.function.Function; /** Resolves all Android component types [activities, services, providers and receivers]. */ public class ComponentResolver { @@ -160,7 +167,7 @@ public class ComponentResolver { /** All available receivers, for your resolving pleasure. */ @GuardedBy("mLock") - private final ActivityIntentResolver mReceivers = new ActivityIntentResolver(); + private final ActivityIntentResolver mReceivers = new ReceiverIntentResolver(); /** All available services, for your resolving pleasure. */ @GuardedBy("mLock") @@ -168,7 +175,7 @@ public class ComponentResolver { /** Mapping from provider authority [first directory in content URI codePath) to provider. */ @GuardedBy("mLock") - private final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority = new ArrayMap<>(); + private final ArrayMap<String, ParsedProvider> mProvidersByAuthority = new ArrayMap<>(); /** Whether or not processing protected filters should be deferred. */ private boolean mDeferProtectedFilters = true; @@ -183,7 +190,7 @@ public class ComponentResolver { * /system partition in order to know which component is the setup wizard. This can * only ever be non-empty if {@link #mDeferProtectedFilters} is {@code true}. */ - private List<PackageParser.ActivityIntentInfo> mProtectedFilters; + private List<ParsedActivityIntentInfo> mProtectedFilters; ComponentResolver(UserManagerService userManager, PackageManagerInternal packageManagerInternal, @@ -194,28 +201,28 @@ public class ComponentResolver { } /** Returns the given activity */ - PackageParser.Activity getActivity(ComponentName component) { + ParsedActivity getActivity(ComponentName component) { synchronized (mLock) { return mActivities.mActivities.get(component); } } /** Returns the given provider */ - PackageParser.Provider getProvider(ComponentName component) { + ParsedProvider getProvider(ComponentName component) { synchronized (mLock) { return mProviders.mProviders.get(component); } } /** Returns the given receiver */ - PackageParser.Activity getReceiver(ComponentName component) { + ParsedActivity getReceiver(ComponentName component) { synchronized (mLock) { return mReceivers.mActivities.get(component); } } /** Returns the given service */ - PackageParser.Service getService(ComponentName component) { + ParsedService getService(ComponentName component) { synchronized (mLock) { return mServices.mServices.get(component); } @@ -230,7 +237,7 @@ public class ComponentResolver { @Nullable List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags, - List<PackageParser.Activity> activities, int userId) { + List<ParsedActivity> activities, int userId) { synchronized (mLock) { return mActivities.queryIntentForPackage( intent, resolvedType, flags, activities, userId); @@ -246,7 +253,7 @@ public class ComponentResolver { @Nullable List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags, - List<PackageParser.Provider> providers, int userId) { + List<ParsedProvider> providers, int userId) { synchronized (mLock) { return mProviders.queryIntentForPackage(intent, resolvedType, flags, providers, userId); } @@ -261,25 +268,34 @@ public class ComponentResolver { List<ProviderInfo> providerList = null; synchronized (mLock) { for (int i = mProviders.mProviders.size() - 1; i >= 0; --i) { - final PackageParser.Provider p = mProviders.mProviders.valueAt(i); - final PackageSetting ps = (PackageSetting) p.owner.mExtras; + final ParsedProvider p = mProviders.mProviders.valueAt(i); + if (p.getAuthority() == null) { + continue; + } + + final PackageSetting ps = + (PackageSetting) sPackageManagerInternal.getPackageSetting( + p.getPackageName()); if (ps == null) { continue; } - if (p.info.authority == null) { + + AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName()); + if (pkg == null) { continue; } - if (processName != null && (!p.info.processName.equals(processName) - || !UserHandle.isSameApp(p.info.applicationInfo.uid, uid))) { + + if (processName != null && (!p.getProcessName().equals(processName) + || !UserHandle.isSameApp(pkg.getUid(), uid))) { continue; } // See PM.queryContentProviders()'s javadoc for why we have the metaData parameter. if (metaDataKey != null - && (p.metaData == null || !p.metaData.containsKey(metaDataKey))) { + && (p.getMetaData() == null || !p.getMetaData().containsKey(metaDataKey))) { continue; } - final ProviderInfo info = PackageParser.generateProviderInfo( - p, flags, ps.readUserState(userId), userId); + final ProviderInfo info = PackageInfoUtils.generateProviderInfo( + pkg, p, flags, ps.readUserState(userId), userId); if (info == null) { continue; } @@ -295,15 +311,21 @@ public class ComponentResolver { @Nullable ProviderInfo queryProvider(String authority, int flags, int userId) { synchronized (mLock) { - final PackageParser.Provider p = mProvidersByAuthority.get(authority); + final ParsedProvider p = mProvidersByAuthority.get(authority); if (p == null) { return null; } - final PackageSetting ps = (PackageSetting) p.owner.mExtras; + final PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + p.getPackageName()); if (ps == null) { return null; } - return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId), userId); + final AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName()); + if (pkg == null) { + return null; + } + return PackageInfoUtils.generateProviderInfo(pkg, p, flags, + ps.readUserState(userId), userId); } } @@ -311,20 +333,29 @@ public class ComponentResolver { int userId) { synchronized (mLock) { for (int i = mProvidersByAuthority.size() - 1; i >= 0; --i) { - final PackageParser.Provider p = mProvidersByAuthority.valueAt(i); - final PackageSetting ps = (PackageSetting) p.owner.mExtras; + final ParsedProvider p = mProvidersByAuthority.valueAt(i); + if (!p.isSyncable()) { + continue; + } + + final PackageSetting ps = + (PackageSetting) sPackageManagerInternal.getPackageSetting( + p.getPackageName()); if (ps == null) { continue; } - if (!p.syncable) { + + final AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName()); + if (pkg == null) { continue; } - if (safeMode - && (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + + if (safeMode && (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) == 0) { continue; } final ProviderInfo info = - PackageParser.generateProviderInfo(p, 0, ps.readUserState(userId), userId); + PackageInfoUtils.generateProviderInfo(pkg, p, 0, + ps.readUserState(userId), userId); if (info == null) { continue; } @@ -343,7 +374,7 @@ public class ComponentResolver { @Nullable List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags, - List<PackageParser.Activity> receivers, int userId) { + List<ParsedActivity> receivers, int userId) { synchronized (mLock) { return mReceivers.queryIntentForPackage(intent, resolvedType, flags, receivers, userId); } @@ -358,7 +389,7 @@ public class ComponentResolver { @Nullable List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags, - List<PackageParser.Service> services, int userId) { + List<ParsedService> services, int userId) { synchronized (mLock) { return mServices.queryIntentForPackage(intent, resolvedType, flags, services, userId); } @@ -372,15 +403,15 @@ public class ComponentResolver { } /** Asserts none of the providers defined in the given package haven't already been defined. */ - void assertProvidersNotDefined(PackageParser.Package pkg) throws PackageManagerException { + void assertProvidersNotDefined(AndroidPackage pkg) throws PackageManagerException { synchronized (mLock) { assertProvidersNotDefinedLocked(pkg); } } /** Add all components defined in the given package to the internal structures. */ - void addAllComponents(PackageParser.Package pkg, boolean chatty) { - final ArrayList<PackageParser.ActivityIntentInfo> newIntents = new ArrayList<>(); + void addAllComponents(AndroidPackage pkg, boolean chatty) { + final ArrayList<ParsedActivityIntentInfo> newIntents = new ArrayList<>(); synchronized (mLock) { addActivitiesLocked(pkg, newIntents, chatty); addReceiversLocked(pkg, chatty); @@ -393,17 +424,19 @@ public class ComponentResolver { PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM)); for (int i = newIntents.size() - 1; i >= 0; --i) { - final PackageParser.ActivityIntentInfo intentInfo = newIntents.get(i); - final PackageParser.Package disabledPkg = sPackageManagerInternal - .getDisabledSystemPackage(intentInfo.activity.info.packageName); - final List<PackageParser.Activity> systemActivities = - disabledPkg != null ? disabledPkg.activities : null; + final ParsedActivityIntentInfo intentInfo = newIntents.get(i); + final PackageSetting disabledPkgSetting = (PackageSetting) sPackageManagerInternal + .getDisabledSystemPackage(intentInfo.getPackageName()); + final AndroidPackage disabledPkg = + disabledPkgSetting == null ? null : disabledPkgSetting.pkg; + final List<ParsedActivity> systemActivities = + disabledPkg != null ? disabledPkg.getActivities() : null; adjustPriority(systemActivities, intentInfo, setupWizardPackage); } } /** Removes all components defined in the given package from the internal structures. */ - void removeAllComponents(PackageParser.Package pkg, boolean chatty) { + void removeAllComponents(AndroidPackage pkg, boolean chatty) { synchronized (mLock) { removeAllComponentsLocked(pkg, chatty); } @@ -422,7 +455,7 @@ public class ComponentResolver { if (mProtectedFilters == null || mProtectedFilters.size() == 0) { return; } - final List<ActivityIntentInfo> protectedFilters = mProtectedFilters; + final List<ParsedActivityIntentInfo> protectedFilters = mProtectedFilters; mProtectedFilters = null; // expect single setupwizard package @@ -435,13 +468,13 @@ public class ComponentResolver { + " All protected intents capped to priority 0"); } for (int i = protectedFilters.size() - 1; i >= 0; --i) { - final ActivityIntentInfo filter = protectedFilters.get(i); - if (filter.activity.info.packageName.equals(setupWizardPackage)) { + final ParsedActivityIntentInfo filter = protectedFilters.get(i); + if (filter.getPackageName().equals(setupWizardPackage)) { if (DEBUG_FILTERS) { Slog.i(TAG, "Found setup wizard;" + " allow priority " + filter.getPriority() + ";" - + " package: " + filter.activity.info.packageName - + " activity: " + filter.activity.className + + " package: " + filter.getPackageName() + + " activity: " + filter.getClassName() + " priority: " + filter.getPriority()); } // skip setup wizard; allow it to keep the high priority filter @@ -449,8 +482,8 @@ public class ComponentResolver { } if (DEBUG_FILTERS) { Slog.i(TAG, "Protected action; cap priority to 0;" - + " package: " + filter.activity.info.packageName - + " activity: " + filter.activity.className + + " package: " + filter.getPackageName() + + " activity: " + filter.getClassName() + " origPrio: " + filter.getPriority()); } filter.setPriority(0); @@ -491,8 +524,8 @@ public class ComponentResolver { void dumpContentProviders(PrintWriter pw, DumpState dumpState, String packageName) { boolean printedSomething = false; - for (PackageParser.Provider p : mProviders.mProviders.values()) { - if (packageName != null && !packageName.equals(p.info.packageName)) { + for (ParsedProvider p : mProviders.mProviders.values()) { + if (packageName != null && !packageName.equals(p.getPackageName())) { continue; } if (!printedSomething) { @@ -502,14 +535,17 @@ public class ComponentResolver { pw.println("Registered ContentProviders:"); printedSomething = true; } - pw.print(" "); p.printComponentShortName(pw); pw.println(":"); - pw.print(" "); pw.println(p.toString()); + pw.print(" "); + ComponentName.printShortString(pw, p.getPackageName(), p.className); + pw.println(":"); + pw.print(" "); + pw.println(p.toString()); } printedSomething = false; - for (Map.Entry<String, PackageParser.Provider> entry : + for (Map.Entry<String, ParsedProvider> entry : mProvidersByAuthority.entrySet()) { - PackageParser.Provider p = entry.getValue(); - if (packageName != null && !packageName.equals(p.info.packageName)) { + ParsedProvider p = entry.getValue(); + if (packageName != null && !packageName.equals(p.getPackageName())) { continue; } if (!printedSomething) { @@ -521,25 +557,43 @@ public class ComponentResolver { } pw.print(" ["); pw.print(entry.getKey()); pw.println("]:"); pw.print(" "); pw.println(p.toString()); - if (p.info != null && p.info.applicationInfo != null) { - final String appInfo = p.info.applicationInfo.toString(); - pw.print(" applicationInfo="); pw.println(appInfo); + + AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName()); + + if (pkg != null) { + // TODO(b/135203078): Print AppInfo? + pw.print(" applicationInfo="); pw.println(pkg.toAppInfoWithoutState()); } } } - void dumpServicePermissions(PrintWriter pw, DumpState dumpState, String packageName) { + void dumpServicePermissions(PrintWriter pw, DumpState dumpState) { if (dumpState.onTitlePrinted()) pw.println(); pw.println("Service permissions:"); - final Iterator<ServiceIntentInfo> filterIterator = mServices.filterIterator(); + final Iterator<ParsedServiceIntentInfo> filterIterator = mServices.filterIterator(); while (filterIterator.hasNext()) { - final ServiceIntentInfo info = filterIterator.next(); - final ServiceInfo serviceInfo = info.service.info; - final String permission = serviceInfo.permission; + final ParsedServiceIntentInfo info = filterIterator.next(); + + ParsedService service = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName()); + if (pkg != null && pkg.getServices() != null) { + for (ParsedService parsedService : pkg.getServices()) { + if (Objects.equals(parsedService.className, info.getClassName())) { + service = parsedService; + } + } + } + + if (service == null) { + continue; + } + + final String permission = service.getPermission(); if (permission != null) { pw.print(" "); - pw.print(serviceInfo.getComponentName().flattenToShortString()); + pw.print(service.getComponentName().flattenToShortString()); pw.print(": "); pw.println(permission); } @@ -547,14 +601,12 @@ public class ComponentResolver { } @GuardedBy("mLock") - private void addActivitiesLocked(PackageParser.Package pkg, - List<PackageParser.ActivityIntentInfo> newIntents, boolean chatty) { - final int activitiesSize = pkg.activities.size(); + private void addActivitiesLocked(AndroidPackage pkg, + List<ParsedActivityIntentInfo> newIntents, boolean chatty) { + final int activitiesSize = ArrayUtils.size(pkg.getActivities()); StringBuilder r = null; for (int i = 0; i < activitiesSize; i++) { - PackageParser.Activity a = pkg.activities.get(i); - a.info.processName = - fixProcessName(pkg.applicationInfo.processName, a.info.processName); + ParsedActivity a = pkg.getActivities().get(i); mActivities.addActivity(a, "activity", newIntents); if (DEBUG_PACKAGE_SCANNING && chatty) { if (r == null) { @@ -562,7 +614,7 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(a.info.name); + r.append(a.getName()); } } if (DEBUG_PACKAGE_SCANNING && chatty) { @@ -571,20 +623,17 @@ public class ComponentResolver { } @GuardedBy("mLock") - private void addProvidersLocked(PackageParser.Package pkg, boolean chatty) { - final int providersSize = pkg.providers.size(); + private void addProvidersLocked(AndroidPackage pkg, boolean chatty) { + final int providersSize = ArrayUtils.size(pkg.getProviders()); StringBuilder r = null; for (int i = 0; i < providersSize; i++) { - PackageParser.Provider p = pkg.providers.get(i); - p.info.processName = fixProcessName(pkg.applicationInfo.processName, - p.info.processName); + EffectiveProvider p = new EffectiveProvider(pkg.getProviders().get(i)); mProviders.addProvider(p); - p.syncable = p.info.isSyncable; - if (p.info.authority != null) { - String[] names = p.info.authority.split(";"); - p.info.authority = null; + if (p.getAuthority() != null) { + String[] names = p.getAuthority().split(";"); + p.setEffectiveAuthority(null); for (int j = 0; j < names.length; j++) { - if (j == 1 && p.syncable) { + if (j == 1 && p.isSyncable()) { // We only want the first authority for a provider to possibly be // syncable, so if we already added this provider using a different // authority clear the syncable flag. We copy the provider before @@ -592,23 +641,23 @@ public class ComponentResolver { // to a provider that we don't want to change. // Only do this for the second authority since the resulting provider // object can be the same for all future authorities for this provider. - p = new PackageParser.Provider(p); - p.syncable = false; + p = new EffectiveProvider(p); + p.setEffectiveSyncable(false); } if (!mProvidersByAuthority.containsKey(names[j])) { mProvidersByAuthority.put(names[j], p); - if (p.info.authority == null) { - p.info.authority = names[j]; + if (p.getAuthority() == null) { + p.setEffectiveAuthority(names[j]); } else { - p.info.authority = p.info.authority + ";" + names[j]; + p.setEffectiveAuthority(p.getAuthority() + ";" + names[j]); } if (DEBUG_PACKAGE_SCANNING && chatty) { Log.d(TAG, "Registered content provider: " + names[j] - + ", className = " + p.info.name - + ", isSyncable = " + p.info.isSyncable); + + ", className = " + p.getName() + + ", isSyncable = " + p.isSyncable()); } } else { - final PackageParser.Provider other = + final ParsedProvider other = mProvidersByAuthority.get(names[j]); final ComponentName component = (other != null && other.getComponentName() != null) @@ -616,7 +665,7 @@ public class ComponentResolver { final String packageName = component != null ? component.getPackageName() : "?"; Slog.w(TAG, "Skipping provider name " + names[j] - + " (in package " + pkg.applicationInfo.packageName + ")" + + " (in package " + pkg.getAppInfoPackageName() + ")" + ": name already used by " + packageName); } } @@ -627,7 +676,7 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(p.info.name); + r.append(p.getName()); } } if (DEBUG_PACKAGE_SCANNING && chatty) { @@ -636,13 +685,11 @@ public class ComponentResolver { } @GuardedBy("mLock") - private void addReceiversLocked(PackageParser.Package pkg, boolean chatty) { - final int receiversSize = pkg.receivers.size(); + private void addReceiversLocked(AndroidPackage pkg, boolean chatty) { + final int receiversSize = ArrayUtils.size(pkg.getReceivers()); StringBuilder r = null; for (int i = 0; i < receiversSize; i++) { - PackageParser.Activity a = pkg.receivers.get(i); - a.info.processName = fixProcessName(pkg.applicationInfo.processName, - a.info.processName); + ParsedActivity a = pkg.getReceivers().get(i); mReceivers.addActivity(a, "receiver", null); if (DEBUG_PACKAGE_SCANNING && chatty) { if (r == null) { @@ -650,7 +697,7 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(a.info.name); + r.append(a.getName()); } } if (DEBUG_PACKAGE_SCANNING && chatty) { @@ -659,13 +706,11 @@ public class ComponentResolver { } @GuardedBy("mLock") - private void addServicesLocked(PackageParser.Package pkg, boolean chatty) { - final int servicesSize = pkg.services.size(); + private void addServicesLocked(AndroidPackage pkg, boolean chatty) { + final int servicesSize = ArrayUtils.size(pkg.getServices()); StringBuilder r = null; for (int i = 0; i < servicesSize; i++) { - PackageParser.Service s = pkg.services.get(i); - s.info.processName = fixProcessName(pkg.applicationInfo.processName, - s.info.processName); + ParsedService s = pkg.getServices().get(i); mServices.addService(s); if (DEBUG_PACKAGE_SCANNING && chatty) { if (r == null) { @@ -673,7 +718,7 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(s.info.name); + r.append(s.getName()); } } if (DEBUG_PACKAGE_SCANNING && chatty) { @@ -681,13 +726,12 @@ public class ComponentResolver { } } - /** * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE * MODIFIED. Do not pass in a list that should not be changed. */ - private static <T> void getIntentListSubset(List<ActivityIntentInfo> intentList, - IterGenerator<T> generator, Iterator<T> searchIterator) { + private static <T> void getIntentListSubset(List<ParsedActivityIntentInfo> intentList, + Function<ParsedActivityIntentInfo, Iterator<T>> generator, Iterator<T> searchIterator) { // loop through the set of actions; every one must be found in the intent filter while (searchIterator.hasNext()) { // we must have at least one filter in the list to consider a match @@ -698,14 +742,14 @@ public class ComponentResolver { final T searchAction = searchIterator.next(); // loop through the set of intent filters - final Iterator<ActivityIntentInfo> intentIter = intentList.iterator(); + final Iterator<ParsedActivityIntentInfo> intentIter = intentList.iterator(); while (intentIter.hasNext()) { - final ActivityIntentInfo intentInfo = intentIter.next(); + final ParsedActivityIntentInfo intentInfo = intentIter.next(); boolean selectionFound = false; // loop through the intent filter's selection criteria; at least one // of them must match the searched criteria - final Iterator<T> intentSelectionIter = generator.generate(intentInfo); + final Iterator<T> intentSelectionIter = generator.apply(intentInfo); while (intentSelectionIter != null && intentSelectionIter.hasNext()) { final T intentSelection = intentSelectionIter.next(); if (intentSelection != null && intentSelection.equals(searchAction)) { @@ -723,7 +767,7 @@ public class ComponentResolver { } } - private static boolean isProtectedAction(ActivityIntentInfo filter) { + private static boolean isProtectedAction(ParsedActivityIntentInfo filter) { final Iterator<String> actionsIter = filter.actionsIterator(); while (actionsIter != null && actionsIter.hasNext()) { final String filterAction = actionsIter.next(); @@ -737,20 +781,20 @@ public class ComponentResolver { /** * Finds a privileged activity that matches the specified activity names. */ - private static PackageParser.Activity findMatchingActivity( - List<PackageParser.Activity> activityList, ActivityInfo activityInfo) { - for (PackageParser.Activity sysActivity : activityList) { - if (sysActivity.info.name.equals(activityInfo.name)) { + private static ParsedActivity findMatchingActivity( + List<ParsedActivity> activityList, ParsedActivity activityInfo) { + for (ParsedActivity sysActivity : activityList) { + if (sysActivity.getName().equals(activityInfo.getName())) { return sysActivity; } - if (sysActivity.info.name.equals(activityInfo.targetActivity)) { + if (sysActivity.getName().equals(activityInfo.targetActivity)) { return sysActivity; } - if (sysActivity.info.targetActivity != null) { - if (sysActivity.info.targetActivity.equals(activityInfo.name)) { + if (sysActivity.targetActivity != null) { + if (sysActivity.targetActivity.equals(activityInfo.getName())) { return sysActivity; } - if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) { + if (sysActivity.targetActivity.equals(activityInfo.targetActivity)) { return sysActivity; } } @@ -771,24 +815,23 @@ public class ComponentResolver { * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is * allowed to obtain any priority on any action. */ - private void adjustPriority(List<PackageParser.Activity> systemActivities, - ActivityIntentInfo intent, String setupWizardPackage) { + private void adjustPriority(List<ParsedActivity> systemActivities, + ParsedActivityIntentInfo intent, String setupWizardPackage) { // nothing to do; priority is fine as-is if (intent.getPriority() <= 0) { return; } - final ActivityInfo activityInfo = intent.activity.info; - final ApplicationInfo applicationInfo = activityInfo.applicationInfo; + AndroidPackage pkg = sPackageManagerInternal.getPackage(intent.getPackageName()); final boolean privilegedApp = - ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0); + ((pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0); if (!privilegedApp) { // non-privileged applications can never define a priority >0 if (DEBUG_FILTERS) { Slog.i(TAG, "Non-privileged app; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -812,8 +855,8 @@ public class ComponentResolver { mProtectedFilters.add(intent); if (DEBUG_FILTERS) { Slog.i(TAG, "Protected action; save for later;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } return; @@ -822,12 +865,12 @@ public class ComponentResolver { Slog.i(TAG, "No setup wizard;" + " All protected intents capped to priority 0"); } - if (intent.activity.info.packageName.equals(setupWizardPackage)) { + if (intent.getPackageName().equals(setupWizardPackage)) { if (DEBUG_FILTERS) { Slog.i(TAG, "Found setup wizard;" + " allow priority " + intent.getPriority() + ";" - + " package: " + intent.activity.info.packageName - + " activity: " + intent.activity.className + + " package: " + intent.getPackageName() + + " activity: " + intent.getClassName() + " priority: " + intent.getPriority()); } // setup wizard gets whatever it wants @@ -835,8 +878,8 @@ public class ComponentResolver { } if (DEBUG_FILTERS) { Slog.i(TAG, "Protected action; cap priority to 0;" - + " package: " + intent.activity.info.packageName - + " activity: " + intent.activity.className + + " package: " + intent.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -848,14 +891,28 @@ public class ComponentResolver { } // privileged app unbundled update ... try to find the same activity - final PackageParser.Activity foundActivity = - findMatchingActivity(systemActivities, activityInfo); + + ParsedActivity foundActivity = null; + ParsedActivity activity = null; + + if (pkg.getActivities() != null) { + for (ParsedActivity parsedProvider : pkg.getActivities()) { + if (Objects.equals(parsedProvider.className, intent.getClassName())) { + activity = parsedProvider; + } + } + } + + if (activity != null) { + foundActivity = findMatchingActivity(systemActivities, activity); + } + if (foundActivity == null) { // this is a new activity; it cannot obtain >0 priority if (DEBUG_FILTERS) { Slog.i(TAG, "New activity; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -865,19 +922,19 @@ public class ComponentResolver { // found activity, now check for filter equivalence // a shallow copy is enough; we modify the list, not its contents - final List<ActivityIntentInfo> intentListCopy = new ArrayList<>(foundActivity.intents); - final List<ActivityIntentInfo> foundFilters = mActivities.findFilters(intent); + final List<ParsedActivityIntentInfo> intentListCopy = + new ArrayList<>(foundActivity.intents); // find matching action subsets final Iterator<String> actionsIterator = intent.actionsIterator(); if (actionsIterator != null) { - getIntentListSubset(intentListCopy, new ActionIterGenerator(), actionsIterator); + getIntentListSubset(intentListCopy, IntentFilter::actionsIterator, actionsIterator); if (intentListCopy.size() == 0) { // no more intents to match; we're not equivalent if (DEBUG_FILTERS) { Slog.i(TAG, "Mismatched action; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -888,13 +945,14 @@ public class ComponentResolver { // find matching category subsets final Iterator<String> categoriesIterator = intent.categoriesIterator(); if (categoriesIterator != null) { - getIntentListSubset(intentListCopy, new CategoriesIterGenerator(), categoriesIterator); + getIntentListSubset(intentListCopy, IntentFilter::categoriesIterator, + categoriesIterator); if (intentListCopy.size() == 0) { // no more intents to match; we're not equivalent if (DEBUG_FILTERS) { Slog.i(TAG, "Mismatched category; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -905,13 +963,13 @@ public class ComponentResolver { // find matching schemes subsets final Iterator<String> schemesIterator = intent.schemesIterator(); if (schemesIterator != null) { - getIntentListSubset(intentListCopy, new SchemesIterGenerator(), schemesIterator); + getIntentListSubset(intentListCopy, IntentFilter::schemesIterator, schemesIterator); if (intentListCopy.size() == 0) { // no more intents to match; we're not equivalent if (DEBUG_FILTERS) { Slog.i(TAG, "Mismatched scheme; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -923,14 +981,14 @@ public class ComponentResolver { final Iterator<IntentFilter.AuthorityEntry> authoritiesIterator = intent.authoritiesIterator(); if (authoritiesIterator != null) { - getIntentListSubset(intentListCopy, new AuthoritiesIterGenerator(), + getIntentListSubset(intentListCopy, IntentFilter::authoritiesIterator, authoritiesIterator); if (intentListCopy.size() == 0) { // no more intents to match; we're not equivalent if (DEBUG_FILTERS) { Slog.i(TAG, "Mismatched authority; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -947,8 +1005,8 @@ public class ComponentResolver { if (DEBUG_FILTERS) { Slog.i(TAG, "Found matching filter(s);" + " cap priority to " + cappedPriority + ";" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(cappedPriority); @@ -958,15 +1016,15 @@ public class ComponentResolver { } @GuardedBy("mLock") - private void removeAllComponentsLocked(PackageParser.Package pkg, boolean chatty) { + private void removeAllComponentsLocked(AndroidPackage pkg, boolean chatty) { int componentSize; StringBuilder r; int i; - componentSize = pkg.activities.size(); + componentSize = ArrayUtils.size(pkg.getActivities()); r = null; for (i = 0; i < componentSize; i++) { - PackageParser.Activity a = pkg.activities.get(i); + ParsedActivity a = pkg.getActivities().get(i); mActivities.removeActivity(a, "activity"); if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -974,32 +1032,32 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(a.info.name); + r.append(a.getName()); } } if (DEBUG_REMOVE && chatty) { Log.d(TAG, " Activities: " + (r == null ? "<NONE>" : r)); } - componentSize = pkg.providers.size(); + componentSize = ArrayUtils.size(pkg.getProviders()); r = null; for (i = 0; i < componentSize; i++) { - PackageParser.Provider p = pkg.providers.get(i); + ParsedProvider p = pkg.getProviders().get(i); mProviders.removeProvider(p); - if (p.info.authority == null) { + if (p.getAuthority() == null) { // Another content provider with this authority existed when this app was // installed, so this authority is null. Ignore it as we don't have to // unregister the provider. continue; } - String[] names = p.info.authority.split(";"); + String[] names = p.getAuthority().split(";"); for (int j = 0; j < names.length; j++) { if (mProvidersByAuthority.get(names[j]) == p) { mProvidersByAuthority.remove(names[j]); if (DEBUG_REMOVE && chatty) { Log.d(TAG, "Unregistered content provider: " + names[j] - + ", className = " + p.info.name + ", isSyncable = " - + p.info.isSyncable); + + ", className = " + p.getName() + ", isSyncable = " + + p.isSyncable()); } } } @@ -1009,17 +1067,17 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(p.info.name); + r.append(p.getName()); } } if (DEBUG_REMOVE && chatty) { Log.d(TAG, " Providers: " + (r == null ? "<NONE>" : r)); } - componentSize = pkg.receivers.size(); + componentSize = ArrayUtils.size(pkg.getReceivers()); r = null; for (i = 0; i < componentSize; i++) { - PackageParser.Activity a = pkg.receivers.get(i); + ParsedActivity a = pkg.getReceivers().get(i); mReceivers.removeActivity(a, "receiver"); if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -1027,17 +1085,17 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(a.info.name); + r.append(a.getName()); } } if (DEBUG_REMOVE && chatty) { Log.d(TAG, " Receivers: " + (r == null ? "<NONE>" : r)); } - componentSize = pkg.services.size(); + componentSize = ArrayUtils.size(pkg.getServices()); r = null; for (i = 0; i < componentSize; i++) { - PackageParser.Service s = pkg.services.get(i); + ParsedService s = pkg.getServices().get(i); mServices.removeService(s); if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -1045,7 +1103,7 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(s.info.name); + r.append(s.getName()); } } if (DEBUG_REMOVE && chatty) { @@ -1054,26 +1112,26 @@ public class ComponentResolver { } @GuardedBy("mLock") - private void assertProvidersNotDefinedLocked(PackageParser.Package pkg) + private void assertProvidersNotDefinedLocked(AndroidPackage pkg) throws PackageManagerException { - final int providersSize = pkg.providers.size(); + final int providersSize = ArrayUtils.size(pkg.getProviders()); int i; for (i = 0; i < providersSize; i++) { - PackageParser.Provider p = pkg.providers.get(i); - if (p.info.authority != null) { - final String[] names = p.info.authority.split(";"); + ParsedProvider p = pkg.getProviders().get(i); + if (p.getAuthority() != null) { + final String[] names = p.getAuthority().split(";"); for (int j = 0; j < names.length; j++) { if (mProvidersByAuthority.containsKey(names[j])) { - final PackageParser.Provider other = mProvidersByAuthority.get(names[j]); + final ParsedProvider other = mProvidersByAuthority.get(names[j]); final String otherPackageName = (other != null && other.getComponentName() != null) ? other.getComponentName().getPackageName() : "?"; // if we're installing over the same already-installed package, this is ok - if (!otherPackageName.equals(pkg.packageName)) { + if (!otherPackageName.equals(pkg.getPackageName())) { throw new PackageManagerException( INSTALL_FAILED_CONFLICTING_PROVIDER, "Can't install because provider name " + names[j] - + " (in package " + pkg.applicationInfo.packageName + + " (in package " + pkg.getPackageName() + ") is already used by " + otherPackageName); } } @@ -1082,8 +1140,9 @@ public class ComponentResolver { } } - private static final class ActivityIntentResolver - extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> { + private static class ActivityIntentResolver + extends IntentResolver<ParsedActivityIntentInfo, ResolveInfo> { + @Override public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { @@ -1104,24 +1163,24 @@ public class ComponentResolver { } List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, - int flags, List<PackageParser.Activity> packageActivities, int userId) { + int flags, List<ParsedActivity> packageActivities, int userId) { if (!sUserManager.exists(userId)) { return null; } if (packageActivities == null) { - return null; + return Collections.emptyList(); } mFlags = flags; final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; final int activitiesSize = packageActivities.size(); - ArrayList<PackageParser.ActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize); + ArrayList<ParsedActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize); - ArrayList<PackageParser.ActivityIntentInfo> intentFilters; + List<ParsedActivityIntentInfo> intentFilters; for (int i = 0; i < activitiesSize; ++i) { intentFilters = packageActivities.get(i).intents; if (intentFilters != null && intentFilters.size() > 0) { - PackageParser.ActivityIntentInfo[] array = - new PackageParser.ActivityIntentInfo[intentFilters.size()]; + ParsedActivityIntentInfo[] array = + new ParsedActivityIntentInfo[intentFilters.size()]; intentFilters.toArray(array); listCut.add(array); } @@ -1129,21 +1188,21 @@ public class ComponentResolver { return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); } - private void addActivity(PackageParser.Activity a, String type, - List<PackageParser.ActivityIntentInfo> newIntents) { + private void addActivity(ParsedActivity a, String type, + List<ParsedActivityIntentInfo> newIntents) { mActivities.put(a.getComponentName(), a); if (DEBUG_SHOW_INFO) { - final CharSequence label = a.info.nonLocalizedLabel != null - ? a.info.nonLocalizedLabel - : a.info.name; + final CharSequence label = a.nonLocalizedLabel != null + ? a.nonLocalizedLabel + : a.getName(); Log.v(TAG, " " + type + " " + label + ":"); } if (DEBUG_SHOW_INFO) { - Log.v(TAG, " Class=" + a.info.name); + Log.v(TAG, " Class=" + a.getName()); } final int intentsSize = a.intents.size(); for (int j = 0; j < intentsSize; j++) { - PackageParser.ActivityIntentInfo intent = a.intents.get(j); + ParsedActivityIntentInfo intent = a.intents.get(j); if (newIntents != null && "activity".equals(type)) { newIntents.add(intent); } @@ -1152,23 +1211,23 @@ public class ComponentResolver { intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } if (!intent.debugCheck()) { - Log.w(TAG, "==> For Activity " + a.info.name); + Log.w(TAG, "==> For Activity " + a.getName()); } addFilter(intent); } } - private void removeActivity(PackageParser.Activity a, String type) { + private void removeActivity(ParsedActivity a, String type) { mActivities.remove(a.getComponentName()); if (DEBUG_SHOW_INFO) { Log.v(TAG, " " + type + " " - + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel - : a.info.name) + ":"); - Log.v(TAG, " Class=" + a.info.name); + + (a.nonLocalizedLabel != null ? a.nonLocalizedLabel + : a.getName()) + ":"); + Log.v(TAG, " Class=" + a.getName()); } final int intentsSize = a.intents.size(); for (int j = 0; j < intentsSize; j++) { - PackageParser.ActivityIntentInfo intent = a.intents.get(j); + ParsedActivityIntentInfo intent = a.intents.get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); @@ -1179,11 +1238,11 @@ public class ComponentResolver { @Override protected boolean allowFilterResult( - PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) { - ActivityInfo filterAi = filter.activity.info; + ParsedActivityIntentInfo filter, List<ResolveInfo> dest) { for (int i = dest.size() - 1; i >= 0; --i) { ActivityInfo destAi = dest.get(i).activityInfo; - if (destAi.name == filterAi.name && destAi.packageName == filterAi.packageName) { + if (Objects.equals(destAi.name, filter.getClassName()) + && Objects.equals(destAi.packageName, filter.getPackageName())) { return false; } } @@ -1191,34 +1250,39 @@ public class ComponentResolver { } @Override - protected ActivityIntentInfo[] newArray(int size) { - return new ActivityIntentInfo[size]; + protected ParsedActivityIntentInfo[] newArray(int size) { + return new ParsedActivityIntentInfo[size]; } @Override - protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) { + protected boolean isFilterStopped(ParsedActivityIntentInfo filter, int userId) { if (!sUserManager.exists(userId)) return true; - PackageParser.Package p = filter.activity.owner; - if (p != null) { - PackageSetting ps = (PackageSetting) p.mExtras; - if (ps != null) { - // System apps are never considered stopped for purposes of - // filtering, because there may be no way for the user to - // actually re-launch them. - return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.getStopped(userId); - } + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg == null) { + return false; } - return false; + + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + filter.getPackageName()); + if (ps == null) { + return false; + } + + // System apps are never considered stopped for purposes of + // filtering, because there may be no way for the user to + // actually re-launch them. + return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 + && ps.getStopped(userId); } @Override protected boolean isPackageForFilter(String packageName, - PackageParser.ActivityIntentInfo info) { - return packageName.equals(info.activity.owner.packageName); + ParsedActivityIntentInfo info) { + return packageName.equals(info.getPackageName()); } - private void log(String reason, ActivityIntentInfo info, int match, + private void log(String reason, ParsedActivityIntentInfo info, int match, int userId) { Slog.w(TAG, reason + "; match: " @@ -1228,7 +1292,7 @@ public class ComponentResolver { } @Override - protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info, + protected ResolveInfo newResult(ParsedActivityIntentInfo info, int match, int userId) { if (!sUserManager.exists(userId)) { if (DEBUG) { @@ -1236,7 +1300,29 @@ public class ComponentResolver { } return null; } - if (!sPackageManagerInternal.isEnabledAndMatches(info.activity.info, mFlags, userId)) { + + ParsedActivity activity = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName()); + if (pkg == null) { + return null; + } + + // TODO(b/135203078): Consider more efficient ways of doing this. + List<ParsedActivity> activities = getResolveList(pkg); + if (activities != null) { + for (ParsedActivity parsedActivity : activities) { + if (Objects.equals(parsedActivity.className, info.getClassName())) { + activity = parsedActivity; + } + } + } + + if (activity == null) { + return null; + } + + if (!sPackageManagerInternal.isEnabledAndMatches(activity, mFlags, userId)) { if (DEBUG) { log("!PackageManagerInternal.isEnabledAndMatches; mFlags=" + DebugUtils.flagsToString(PackageManager.class, "MATCH_", mFlags), @@ -1244,8 +1330,8 @@ public class ComponentResolver { } return null; } - final PackageParser.Activity activity = info.activity; - PackageSetting ps = (PackageSetting) activity.owner.mExtras; + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + info.getPackageName()); if (ps == null) { if (DEBUG) { log("info.activity.owner.mExtras == null", info, match, userId); @@ -1254,10 +1340,10 @@ public class ComponentResolver { } final PackageUserState userState = ps.readUserState(userId); ActivityInfo ai = - PackageParser.generateActivityInfo(activity, mFlags, userState, userId); + PackageInfoUtils.generateActivityInfo(pkg, activity, mFlags, userState, userId); if (ai == null) { if (DEBUG) { - log("Failed to create ActivityInfo based on " + info.activity, info, match, + log("Failed to create ActivityInfo based on " + activity, info, match, userId); } return null; @@ -1307,7 +1393,7 @@ public class ComponentResolver { } res.handleAllWebDataURI = info.handleAllWebDataURI(); res.priority = info.getPriority(); - res.preferredOrder = activity.owner.mPreferredOrder; + res.preferredOrder = pkg.getPreferredOrder(); //System.out.println("Result: " + res.activityInfo.className + // " = " + res.priority); res.match = match; @@ -1332,40 +1418,64 @@ public class ComponentResolver { @Override protected void dumpFilter(PrintWriter out, String prefix, - PackageParser.ActivityIntentInfo filter) { + ParsedActivityIntentInfo filter) { + ParsedActivity activity = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg != null && pkg.getActivities() != null) { + for (ParsedActivity parsedActivity : pkg.getActivities()) { + if (Objects.equals(parsedActivity.className, filter.getClassName())) { + activity = parsedActivity; + } + } + } + out.print(prefix); - out.print(Integer.toHexString(System.identityHashCode(filter.activity))); + out.print(Integer.toHexString(System.identityHashCode(activity))); out.print(' '); - filter.activity.printComponentShortName(out); + ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName()); out.print(" filter "); out.println(Integer.toHexString(System.identityHashCode(filter))); } @Override - protected Object filterToLabel(PackageParser.ActivityIntentInfo filter) { - return filter.activity; + protected Object filterToLabel(ParsedActivityIntentInfo filter) { + return filter; } protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { - PackageParser.Activity activity = (PackageParser.Activity) label; + ParsedActivityIntentInfo activity = (ParsedActivityIntentInfo) label; out.print(prefix); out.print(Integer.toHexString(System.identityHashCode(activity))); out.print(' '); - activity.printComponentShortName(out); + ComponentName.printShortString(out, activity.getPackageName(), activity.getClassName()); if (count > 1) { out.print(" ("); out.print(count); out.print(" filters)"); } out.println(); } + protected List<ParsedActivity> getResolveList(AndroidPackage pkg) { + return pkg.getActivities(); + } + // Keys are String (activity class name), values are Activity. - private final ArrayMap<ComponentName, PackageParser.Activity> mActivities = + private final ArrayMap<ComponentName, ParsedActivity> mActivities = new ArrayMap<>(); private int mFlags; } + // Both receivers and activities share a class, but point to different get methods + private static final class ReceiverIntentResolver extends ActivityIntentResolver { + + @Override + protected List<ParsedActivity> getResolveList(AndroidPackage pkg) { + return pkg.getReceivers(); + } + } + private static final class ProviderIntentResolver - extends IntentResolver<PackageParser.ProviderIntentInfo, ResolveInfo> { + extends IntentResolver<ParsedProviderIntentInfo, ResolveInfo> { @Override public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { @@ -1387,24 +1497,24 @@ public class ComponentResolver { @Nullable List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, - int flags, List<PackageParser.Provider> packageProviders, int userId) { + int flags, List<ParsedProvider> packageProviders, int userId) { if (!sUserManager.exists(userId)) { return null; } if (packageProviders == null) { - return null; + return Collections.emptyList(); } mFlags = flags; final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; final int providersSize = packageProviders.size(); - ArrayList<PackageParser.ProviderIntentInfo[]> listCut = new ArrayList<>(providersSize); + ArrayList<ParsedProviderIntentInfo[]> listCut = new ArrayList<>(providersSize); - ArrayList<PackageParser.ProviderIntentInfo> intentFilters; + List<ParsedProviderIntentInfo> intentFilters; for (int i = 0; i < providersSize; ++i) { - intentFilters = packageProviders.get(i).intents; + intentFilters = packageProviders.get(i).getIntents(); if (intentFilters != null && intentFilters.size() > 0) { - PackageParser.ProviderIntentInfo[] array = - new PackageParser.ProviderIntentInfo[intentFilters.size()]; + ParsedProviderIntentInfo[] array = + new ParsedProviderIntentInfo[intentFilters.size()]; intentFilters.toArray(array); listCut.add(array); } @@ -1412,7 +1522,7 @@ public class ComponentResolver { return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); } - void addProvider(PackageParser.Provider p) { + void addProvider(ParsedProvider p) { if (mProviders.containsKey(p.getComponentName())) { Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring"); return; @@ -1421,39 +1531,39 @@ public class ComponentResolver { mProviders.put(p.getComponentName(), p); if (DEBUG_SHOW_INFO) { Log.v(TAG, " " - + (p.info.nonLocalizedLabel != null - ? p.info.nonLocalizedLabel - : p.info.name) + + (p.nonLocalizedLabel != null + ? p.nonLocalizedLabel + : p.getName()) + ":"); - Log.v(TAG, " Class=" + p.info.name); + Log.v(TAG, " Class=" + p.getName()); } - final int intentsSize = p.intents.size(); + final int intentsSize = p.getIntents().size(); int j; for (j = 0; j < intentsSize; j++) { - PackageParser.ProviderIntentInfo intent = p.intents.get(j); + ParsedProviderIntentInfo intent = p.getIntents().get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } if (!intent.debugCheck()) { - Log.w(TAG, "==> For Provider " + p.info.name); + Log.w(TAG, "==> For Provider " + p.getName()); } addFilter(intent); } } - void removeProvider(PackageParser.Provider p) { + void removeProvider(ParsedProvider p) { mProviders.remove(p.getComponentName()); if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " + (p.info.nonLocalizedLabel != null - ? p.info.nonLocalizedLabel - : p.info.name) + ":"); - Log.v(TAG, " Class=" + p.info.name); + Log.v(TAG, " " + (p.nonLocalizedLabel != null + ? p.nonLocalizedLabel + : p.getName()) + ":"); + Log.v(TAG, " Class=" + p.getName()); } - final int intentsSize = p.intents.size(); + final int intentsSize = p.getIntents().size(); int j; for (j = 0; j < intentsSize; j++) { - PackageParser.ProviderIntentInfo intent = p.intents.get(j); + ParsedProviderIntentInfo intent = p.getIntents().get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); @@ -1464,12 +1574,11 @@ public class ComponentResolver { @Override protected boolean allowFilterResult( - PackageParser.ProviderIntentInfo filter, List<ResolveInfo> dest) { - ProviderInfo filterPi = filter.provider.info; + ParsedProviderIntentInfo filter, List<ResolveInfo> dest) { for (int i = dest.size() - 1; i >= 0; i--) { ProviderInfo destPi = dest.get(i).providerInfo; - if (destPi.name == filterPi.name - && destPi.packageName == filterPi.packageName) { + if (Objects.equals(destPi.name, filter.getClassName()) + && Objects.equals(destPi.packageName, filter.getPackageName())) { return false; } } @@ -1477,47 +1586,68 @@ public class ComponentResolver { } @Override - protected PackageParser.ProviderIntentInfo[] newArray(int size) { - return new PackageParser.ProviderIntentInfo[size]; + protected ParsedProviderIntentInfo[] newArray(int size) { + return new ParsedProviderIntentInfo[size]; } @Override - protected boolean isFilterStopped(PackageParser.ProviderIntentInfo filter, int userId) { + protected boolean isFilterStopped(ParsedProviderIntentInfo filter, int userId) { if (!sUserManager.exists(userId)) { return true; } - PackageParser.Package p = filter.provider.owner; - if (p != null) { - PackageSetting ps = (PackageSetting) p.mExtras; - if (ps != null) { - // System apps are never considered stopped for purposes of - // filtering, because there may be no way for the user to - // actually re-launch them. - return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.getStopped(userId); - } + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg == null) { + return false; + } + + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + filter.getPackageName()); + if (ps == null) { + return false; } - return false; + + // System apps are never considered stopped for purposes of + // filtering, because there may be no way for the user to + // actually re-launch them. + return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 + && ps.getStopped(userId); } @Override protected boolean isPackageForFilter(String packageName, - PackageParser.ProviderIntentInfo info) { - return packageName.equals(info.provider.owner.packageName); + ParsedProviderIntentInfo info) { + return packageName.equals(info.getPackageName()); } @Override - protected ResolveInfo newResult(PackageParser.ProviderIntentInfo filter, + protected ResolveInfo newResult(ParsedProviderIntentInfo filter, int match, int userId) { if (!sUserManager.exists(userId)) { return null; } - final PackageParser.ProviderIntentInfo info = filter; - if (!sPackageManagerInternal.isEnabledAndMatches(info.provider.info, mFlags, userId)) { + + ParsedProvider provider = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg != null && pkg.getProviders() != null) { + for (ParsedProvider parsedProvider : pkg.getProviders()) { + if (Objects.equals(parsedProvider.className, filter.getClassName())) { + provider = parsedProvider; + } + } + } + + if (provider == null) { + return null; + } + + if (!sPackageManagerInternal.isEnabledAndMatches(provider, mFlags, userId)) { return null; } - final PackageParser.Provider provider = info.provider; - PackageSetting ps = (PackageSetting) provider.owner.mExtras; + + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + filter.getPackageName()); if (ps == null) { return null; } @@ -1527,7 +1657,7 @@ public class ComponentResolver { final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0; // throw out filters that aren't visible to instant applications if (matchVisibleToInstantApp - && !(info.isVisibleToInstantApp() || userState.instantApp)) { + && !(filter.isVisibleToInstantApp() || userState.instantApp)) { return null; } // throw out instant application filters if we're not explicitly requesting them @@ -1539,8 +1669,8 @@ public class ComponentResolver { if (userState.instantApp && ps.isUpdateAvailable()) { return null; } - ProviderInfo pi = PackageParser.generateProviderInfo(provider, mFlags, - userState, userId); + ProviderInfo pi = PackageInfoUtils.generateProviderInfo(pkg, provider, + mFlags, userState, userId); if (pi == null) { return null; } @@ -1549,13 +1679,13 @@ public class ComponentResolver { if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) { res.filter = filter; } - res.priority = info.getPriority(); - res.preferredOrder = provider.owner.mPreferredOrder; + res.priority = filter.getPriority(); + res.preferredOrder = pkg.getPreferredOrder(); res.match = match; - res.isDefault = info.hasDefault; - res.labelRes = info.labelRes; - res.nonLocalizedLabel = info.nonLocalizedLabel; - res.icon = info.icon; + res.isDefault = filter.hasDefault; + res.labelRes = filter.labelRes; + res.nonLocalizedLabel = filter.nonLocalizedLabel; + res.icon = filter.icon; res.system = res.providerInfo.applicationInfo.isSystemApp(); return res; } @@ -1567,26 +1697,37 @@ public class ComponentResolver { @Override protected void dumpFilter(PrintWriter out, String prefix, - PackageParser.ProviderIntentInfo filter) { + ParsedProviderIntentInfo filter) { + ParsedProvider provider = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg != null && pkg.getProviders() != null) { + for (ParsedProvider parsedProvider : pkg.getProviders()) { + if (Objects.equals(parsedProvider.className, filter.getClassName())) { + provider = parsedProvider; + } + } + } + out.print(prefix); - out.print(Integer.toHexString(System.identityHashCode(filter.provider))); + out.print(Integer.toHexString(System.identityHashCode(provider))); out.print(' '); - filter.provider.printComponentShortName(out); + ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName()); out.print(" filter "); out.println(Integer.toHexString(System.identityHashCode(filter))); } @Override - protected Object filterToLabel(PackageParser.ProviderIntentInfo filter) { - return filter.provider; + protected Object filterToLabel(ParsedProviderIntentInfo filter) { + return filter; } protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { - final PackageParser.Provider provider = (PackageParser.Provider) label; + final ParsedProviderIntentInfo provider = (ParsedProviderIntentInfo) label; out.print(prefix); out.print(Integer.toHexString(System.identityHashCode(provider))); out.print(' '); - provider.printComponentShortName(out); + ComponentName.printShortString(out, provider.getPackageName(), provider.getClassName()); if (count > 1) { out.print(" ("); out.print(count); @@ -1595,12 +1736,12 @@ public class ComponentResolver { out.println(); } - private final ArrayMap<ComponentName, PackageParser.Provider> mProviders = new ArrayMap<>(); + private final ArrayMap<ComponentName, ParsedProvider> mProviders = new ArrayMap<>(); private int mFlags; } private static final class ServiceIntentResolver - extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> { + extends IntentResolver<ParsedServiceIntentInfo, ResolveInfo> { @Override public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { @@ -1618,22 +1759,22 @@ public class ComponentResolver { } List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, - int flags, List<PackageParser.Service> packageServices, int userId) { + int flags, List<ParsedService> packageServices, int userId) { if (!sUserManager.exists(userId)) return null; if (packageServices == null) { - return null; + return Collections.emptyList(); } mFlags = flags; final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; final int servicesSize = packageServices.size(); - ArrayList<PackageParser.ServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize); + ArrayList<ParsedServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize); - ArrayList<PackageParser.ServiceIntentInfo> intentFilters; + List<ParsedServiceIntentInfo> intentFilters; for (int i = 0; i < servicesSize; ++i) { intentFilters = packageServices.get(i).intents; if (intentFilters != null && intentFilters.size() > 0) { - PackageParser.ServiceIntentInfo[] array = - new PackageParser.ServiceIntentInfo[intentFilters.size()]; + ParsedServiceIntentInfo[] array = + new ParsedServiceIntentInfo[intentFilters.size()]; intentFilters.toArray(array); listCut.add(array); } @@ -1641,40 +1782,40 @@ public class ComponentResolver { return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); } - void addService(PackageParser.Service s) { + void addService(ParsedService s) { mServices.put(s.getComponentName(), s); if (DEBUG_SHOW_INFO) { Log.v(TAG, " " - + (s.info.nonLocalizedLabel != null - ? s.info.nonLocalizedLabel : s.info.name) + ":"); - Log.v(TAG, " Class=" + s.info.name); + + (s.nonLocalizedLabel != null + ? s.nonLocalizedLabel : s.getName()) + ":"); + Log.v(TAG, " Class=" + s.getName()); } final int intentsSize = s.intents.size(); int j; for (j = 0; j < intentsSize; j++) { - PackageParser.ServiceIntentInfo intent = s.intents.get(j); + ParsedServiceIntentInfo intent = s.intents.get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } if (!intent.debugCheck()) { - Log.w(TAG, "==> For Service " + s.info.name); + Log.w(TAG, "==> For Service " + s.getName()); } addFilter(intent); } } - void removeService(PackageParser.Service s) { + void removeService(ParsedService s) { mServices.remove(s.getComponentName()); if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " + (s.info.nonLocalizedLabel != null - ? s.info.nonLocalizedLabel : s.info.name) + ":"); - Log.v(TAG, " Class=" + s.info.name); + Log.v(TAG, " " + (s.nonLocalizedLabel != null + ? s.nonLocalizedLabel : s.getName()) + ":"); + Log.v(TAG, " Class=" + s.getName()); } final int intentsSize = s.intents.size(); int j; for (j = 0; j < intentsSize; j++) { - PackageParser.ServiceIntentInfo intent = s.intents.get(j); + ParsedServiceIntentInfo intent = s.intents.get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); @@ -1685,12 +1826,11 @@ public class ComponentResolver { @Override protected boolean allowFilterResult( - PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) { - ServiceInfo filterSi = filter.service.info; + ParsedServiceIntentInfo filter, List<ResolveInfo> dest) { for (int i = dest.size() - 1; i >= 0; --i) { ServiceInfo destAi = dest.get(i).serviceInfo; - if (destAi.name == filterSi.name - && destAi.packageName == filterSi.packageName) { + if (Objects.equals(destAi.name, filter.getClassName()) + && Objects.equals(destAi.packageName, filter.getPackageName())) { return false; } } @@ -1698,48 +1838,69 @@ public class ComponentResolver { } @Override - protected PackageParser.ServiceIntentInfo[] newArray(int size) { - return new PackageParser.ServiceIntentInfo[size]; + protected ParsedServiceIntentInfo[] newArray(int size) { + return new ParsedServiceIntentInfo[size]; } @Override - protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) { + protected boolean isFilterStopped(ParsedServiceIntentInfo filter, int userId) { if (!sUserManager.exists(userId)) return true; - PackageParser.Package p = filter.service.owner; - if (p != null) { - PackageSetting ps = (PackageSetting) p.mExtras; - if (ps != null) { - // System apps are never considered stopped for purposes of - // filtering, because there may be no way for the user to - // actually re-launch them. - return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.getStopped(userId); - } + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg == null) { + return false; } - return false; + + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + filter.getPackageName()); + if (ps == null) { + return false; + } + + // System apps are never considered stopped for purposes of + // filtering, because there may be no way for the user to + // actually re-launch them. + return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 + && ps.getStopped(userId); } @Override protected boolean isPackageForFilter(String packageName, - PackageParser.ServiceIntentInfo info) { - return packageName.equals(info.service.owner.packageName); + ParsedServiceIntentInfo info) { + return packageName.equals(info.getPackageName()); } @Override - protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter, + protected ResolveInfo newResult(ParsedServiceIntentInfo filter, int match, int userId) { if (!sUserManager.exists(userId)) return null; - final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo) filter; - if (!sPackageManagerInternal.isEnabledAndMatches(info.service.info, mFlags, userId)) { + + ParsedService service = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg != null && pkg.getServices() != null) { + for (ParsedService parsedService : pkg.getServices()) { + if (Objects.equals(parsedService.className, filter.getClassName())) { + service = parsedService; + } + } + } + + if (service == null) { + return null; + } + + if (!sPackageManagerInternal.isEnabledAndMatches(service, mFlags, userId)) { return null; } - final PackageParser.Service service = info.service; - PackageSetting ps = (PackageSetting) service.owner.mExtras; + + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + filter.getPackageName()); if (ps == null) { return null; } final PackageUserState userState = ps.readUserState(userId); - ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags, + ServiceInfo si = PackageInfoUtils.generateServiceInfo(pkg, service, mFlags, userState, userId); if (si == null) { return null; @@ -1749,7 +1910,7 @@ public class ComponentResolver { final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0; // throw out filters that aren't visible to ephemeral apps if (matchVisibleToInstantApp - && !(info.isVisibleToInstantApp() || userState.instantApp)) { + && !(filter.isVisibleToInstantApp() || userState.instantApp)) { return null; } // throw out ephemeral filters if we're not explicitly requesting them @@ -1766,13 +1927,13 @@ public class ComponentResolver { if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) { res.filter = filter; } - res.priority = info.getPriority(); - res.preferredOrder = service.owner.mPreferredOrder; + res.priority = filter.getPriority(); + res.preferredOrder = pkg.getPreferredOrder(); res.match = match; - res.isDefault = info.hasDefault; - res.labelRes = info.labelRes; - res.nonLocalizedLabel = info.nonLocalizedLabel; - res.icon = info.icon; + res.isDefault = filter.hasDefault; + res.labelRes = filter.labelRes; + res.nonLocalizedLabel = filter.nonLocalizedLabel; + res.icon = filter.icon; res.system = res.serviceInfo.applicationInfo.isSystemApp(); return res; } @@ -1784,31 +1945,42 @@ public class ComponentResolver { @Override protected void dumpFilter(PrintWriter out, String prefix, - PackageParser.ServiceIntentInfo filter) { + ParsedServiceIntentInfo filter) { + ParsedService service = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg != null && pkg.getServices() != null) { + for (ParsedService parsedService : pkg.getServices()) { + if (Objects.equals(parsedService.className, filter.getClassName())) { + service = parsedService; + } + } + } + out.print(prefix); - out.print(Integer.toHexString(System.identityHashCode(filter.service))); + out.print(Integer.toHexString(System.identityHashCode(service))); out.print(' '); - filter.service.printComponentShortName(out); + ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName()); out.print(" filter "); out.print(Integer.toHexString(System.identityHashCode(filter))); - if (filter.service.info.permission != null) { - out.print(" permission "); out.println(filter.service.info.permission); + if (service != null && service.getPermission() != null) { + out.print(" permission "); out.println(service.getPermission()); } else { out.println(); } } @Override - protected Object filterToLabel(PackageParser.ServiceIntentInfo filter) { - return filter.service; + protected Object filterToLabel(ParsedServiceIntentInfo filter) { + return filter; } protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { - final PackageParser.Service service = (PackageParser.Service) label; + final ParsedServiceIntentInfo service = (ParsedServiceIntentInfo) label; out.print(prefix); out.print(Integer.toHexString(System.identityHashCode(service))); out.print(' '); - service.printComponentShortName(out); + ComponentName.printShortString(out, service.getPackageName(), service.getClassName()); if (count > 1) { out.print(" ("); out.print(count); out.print(" filters)"); } @@ -1816,7 +1988,7 @@ public class ComponentResolver { } // Keys are String (activity class name), values are Activity. - private final ArrayMap<ComponentName, PackageParser.Service> mServices = new ArrayMap<>(); + private final ArrayMap<ComponentName, ParsedService> mServices = new ArrayMap<>(); private int mFlags; } @@ -1905,7 +2077,7 @@ public class ComponentResolver { /** Generic to create an {@link Iterator} for a data type */ static class IterGenerator<E> { - public Iterator<E> generate(ActivityIntentInfo info) { + public Iterator<E> generate(ParsedActivityIntentInfo info) { return null; } } @@ -1913,7 +2085,7 @@ public class ComponentResolver { /** Create an {@link Iterator} for intent actions */ static class ActionIterGenerator extends IterGenerator<String> { @Override - public Iterator<String> generate(ActivityIntentInfo info) { + public Iterator<String> generate(ParsedActivityIntentInfo info) { return info.actionsIterator(); } } @@ -1921,7 +2093,7 @@ public class ComponentResolver { /** Create an {@link Iterator} for intent categories */ static class CategoriesIterGenerator extends IterGenerator<String> { @Override - public Iterator<String> generate(ActivityIntentInfo info) { + public Iterator<String> generate(ParsedActivityIntentInfo info) { return info.categoriesIterator(); } } @@ -1929,7 +2101,7 @@ public class ComponentResolver { /** Create an {@link Iterator} for intent schemes */ static class SchemesIterGenerator extends IterGenerator<String> { @Override - public Iterator<String> generate(ActivityIntentInfo info) { + public Iterator<String> generate(ParsedActivityIntentInfo info) { return info.schemesIterator(); } } @@ -1937,9 +2109,39 @@ public class ComponentResolver { /** Create an {@link Iterator} for intent authorities */ static class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> { @Override - public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) { + public Iterator<IntentFilter.AuthorityEntry> generate(ParsedActivityIntentInfo info) { return info.authoritiesIterator(); } } + // TODO(b/135203078): Document or remove this if possible. + class EffectiveProvider extends ParsedProvider { + + private String mEffectiveAuthority; + private boolean mEffectiveSyncable; + + public EffectiveProvider(ParsedProvider parsedProvider) { + this.setFrom(parsedProvider); + this.mEffectiveAuthority = parsedProvider.getAuthority(); + this.mEffectiveSyncable = parsedProvider.isSyncable(); + } + + public void setEffectiveAuthority(String authority) { + this.mEffectiveAuthority = authority; + } + + public void setEffectiveSyncable(boolean syncable) { + this.mEffectiveSyncable = syncable; + } + + @Override + public String getAuthority() { + return mEffectiveAuthority; + } + + @Override + public boolean isSyncable() { + return mEffectiveSyncable; + } + } } diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java index 9e04c4b69bd0..ffcd6cf8603c 100644 --- a/services/core/java/com/android/server/pm/InstantAppRegistry.java +++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java @@ -20,9 +20,12 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.InstantAppInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageInfoUtils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; @@ -137,7 +140,7 @@ class InstantAppRegistry { public byte[] getInstantAppCookieLPw(@NonNull String packageName, @UserIdInt int userId) { // Only installed packages can get their own cookie - PackageParser.Package pkg = mService.mPackages.get(packageName); + AndroidPackage pkg = mService.mPackages.get(packageName); if (pkg == null) { return null; } @@ -171,7 +174,7 @@ class InstantAppRegistry { } // Only an installed package can set its own cookie - PackageParser.Package pkg = mService.mPackages.get(packageName); + AndroidPackage pkg = mService.mPackages.get(packageName); if (pkg == null) { return false; } @@ -264,15 +267,15 @@ class InstantAppRegistry { } @GuardedBy("mService.mLock") - public void onPackageInstalledLPw(@NonNull PackageParser.Package pkg, @NonNull int[] userIds) { - PackageSetting ps = (PackageSetting) pkg.mExtras; + public void onPackageInstalledLPw(@NonNull AndroidPackage pkg, @NonNull int[] userIds) { + PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); if (ps == null) { return; } for (int userId : userIds) { // Ignore not installed apps - if (mService.mPackages.get(pkg.packageName) == null || !ps.getInstalled(userId)) { + if (mService.mPackages.get(pkg.getPackageName()) == null || !ps.getInstalled(userId)) { continue; } @@ -286,16 +289,16 @@ class InstantAppRegistry { // Remove the in-memory state removeUninstalledInstantAppStateLPw((UninstalledInstantAppState state) -> - state.mInstantAppInfo.getPackageName().equals(pkg.packageName), + state.mInstantAppInfo.getPackageName().equals(pkg.getPackageName()), userId); // Remove the on-disk state except the cookie - File instantAppDir = getInstantApplicationDir(pkg.packageName, userId); + File instantAppDir = getInstantApplicationDir(pkg.getPackageName(), userId); new File(instantAppDir, INSTANT_APP_METADATA_FILE).delete(); new File(instantAppDir, INSTANT_APP_ICON_FILE).delete(); // If app signature changed - wipe the cookie - File currentCookieFile = peekInstantCookieFile(pkg.packageName, userId); + File currentCookieFile = peekInstantCookieFile(pkg.getPackageName(), userId); if (currentCookieFile == null) { continue; } @@ -310,7 +313,7 @@ class InstantAppRegistry { // We prefer the modern computation procedure where all certs are taken // into account but also allow the value from the old computation to avoid // data loss. - if (pkg.mSigningDetails.checkCapability(currentCookieSha256, + if (pkg.getSigningDetails().checkCapability(currentCookieSha256, PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) { return; } @@ -318,7 +321,7 @@ class InstantAppRegistry { // For backwards compatibility we accept match based on any signature, since we may have // recorded only the first for multiply-signed packages final String[] signaturesSha256Digests = - PackageUtils.computeSignaturesSha256Digests(pkg.mSigningDetails.signatures); + PackageUtils.computeSignaturesSha256Digests(pkg.getSigningDetails().signatures); for (String s : signaturesSha256Digests) { if (s.equals(currentCookieSha256)) { return; @@ -326,7 +329,7 @@ class InstantAppRegistry { } // Sorry, you are out of luck - different signatures - nuke data - Slog.i(LOG_TAG, "Signature for package " + pkg.packageName + Slog.i(LOG_TAG, "Signature for package " + pkg.getPackageName() + " changed - dropping cookie"); // Make sure a pending write for the old signed app is cancelled mCookiePersistence.cancelPendingPersistLPw(pkg, userId); @@ -335,15 +338,15 @@ class InstantAppRegistry { } @GuardedBy("mService.mLock") - public void onPackageUninstalledLPw(@NonNull PackageParser.Package pkg, + public void onPackageUninstalledLPw(@NonNull AndroidPackage pkg, @NonNull int[] userIds) { - PackageSetting ps = (PackageSetting) pkg.mExtras; + PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); if (ps == null) { return; } for (int userId : userIds) { - if (mService.mPackages.get(pkg.packageName) != null && ps.getInstalled(userId)) { + if (mService.mPackages.get(pkg.getPackageName()) != null && ps.getInstalled(userId)) { continue; } @@ -353,7 +356,7 @@ class InstantAppRegistry { removeInstantAppLPw(userId, ps.appId); } else { // Deleting an app prunes all instant state such as cookie - deleteDir(getInstantApplicationDir(pkg.packageName, userId)); + deleteDir(getInstantApplicationDir(pkg.getPackageName(), userId)); mCookiePersistence.cancelPendingPersistLPw(pkg, userId); removeAppLPw(userId, ps.appId); } @@ -487,7 +490,7 @@ class InstantAppRegistry { } @GuardedBy("mService.mLock") - private void addUninstalledInstantAppLPw(@NonNull PackageParser.Package pkg, + private void addUninstalledInstantAppLPw(@NonNull AndroidPackage pkg, @UserIdInt int userId) { InstantAppInfo uninstalledApp = createInstantAppInfoForPackage( pkg, userId, false); @@ -511,14 +514,15 @@ class InstantAppRegistry { writeInstantApplicationIconLPw(pkg, userId); } - private void writeInstantApplicationIconLPw(@NonNull PackageParser.Package pkg, + private void writeInstantApplicationIconLPw(@NonNull AndroidPackage pkg, @UserIdInt int userId) { - File appDir = getInstantApplicationDir(pkg.packageName, userId); + File appDir = getInstantApplicationDir(pkg.getPackageName(), userId); if (!appDir.exists()) { return; } - Drawable icon = pkg.applicationInfo.loadIcon(mService.mContext.getPackageManager()); + // TODO(b/135203078): Remove toAppInfo call? Requires significant additions/changes to PM + Drawable icon = pkg.toAppInfoWithoutState().loadIcon(mService.mContext.getPackageManager()); final Bitmap bitmap; if (icon instanceof BitmapDrawable) { @@ -531,7 +535,7 @@ class InstantAppRegistry { icon.draw(canvas); } - File iconFile = new File(getInstantApplicationDir(pkg.packageName, userId), + File iconFile = new File(getInstantApplicationDir(pkg.getPackageName(), userId), INSTANT_APP_ICON_FILE); try (FileOutputStream out = new FileOutputStream(iconFile)) { @@ -690,14 +694,16 @@ class InstantAppRegistry { final int packageCount = mService.mPackages.size(); for (int i = 0; i < packageCount; i++) { - final PackageParser.Package pkg = mService.mPackages.valueAt(i); + final AndroidPackage pkg = mService.mPackages.valueAt(i); if (now - pkg.getLatestPackageUseTimeInMills() < maxInstalledCacheDuration) { continue; } - if (!(pkg.mExtras instanceof PackageSetting)) { + + final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); + if (ps == null) { continue; } - final PackageSetting ps = (PackageSetting) pkg.mExtras; + boolean installedOnlyAsInstantApp = false; for (int userId : allUsers) { if (ps.getInstalled(userId)) { @@ -713,14 +719,14 @@ class InstantAppRegistry { if (packagesToDelete == null) { packagesToDelete = new ArrayList<>(); } - packagesToDelete.add(pkg.packageName); + packagesToDelete.add(pkg.getPackageName()); } } if (packagesToDelete != null) { packagesToDelete.sort((String lhs, String rhs) -> { - final PackageParser.Package lhsPkg = mService.mPackages.get(lhs); - final PackageParser.Package rhsPkg = mService.mPackages.get(rhs); + final AndroidPackage lhsPkg = mService.mPackages.get(lhs); + final AndroidPackage rhsPkg = mService.mPackages.get(rhs); if (lhsPkg == null && rhsPkg == null) { return 0; } else if (lhsPkg == null) { @@ -735,18 +741,23 @@ class InstantAppRegistry { rhsPkg.getLatestPackageUseTimeInMills()) { return -1; } else { - if (lhsPkg.mExtras instanceof PackageSetting - && rhsPkg.mExtras instanceof PackageSetting) { - final PackageSetting lhsPs = (PackageSetting) lhsPkg.mExtras; - final PackageSetting rhsPs = (PackageSetting) rhsPkg.mExtras; - if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) { - return 1; - } else { - return -1; - } - } else { + final PackageSetting lhsPs = mService.getPackageSetting( + lhsPkg.getPackageName()); + if (lhsPs == null) { + return 0; + } + + final PackageSetting rhsPs = mService.getPackageSetting( + rhsPkg.getPackageName()); + if (rhsPs == null) { return 0; } + + if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) { + return 1; + } else { + return -1; + } } } }); @@ -818,8 +829,8 @@ class InstantAppRegistry { final int packageCount = mService.mPackages.size(); for (int i = 0; i < packageCount; i++) { - final PackageParser.Package pkg = mService.mPackages.valueAt(i); - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final AndroidPackage pkg = mService.mPackages.valueAt(i); + final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); if (ps == null || !ps.getInstantApp(userId)) { continue; } @@ -839,9 +850,9 @@ class InstantAppRegistry { private @NonNull InstantAppInfo createInstantAppInfoForPackage( - @NonNull PackageParser.Package pkg, @UserIdInt int userId, + @NonNull AndroidPackage pkg, @UserIdInt int userId, boolean addApplicationInfo) { - PackageSetting ps = (PackageSetting) pkg.mExtras; + PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); if (ps == null) { return null; } @@ -849,19 +860,23 @@ class InstantAppRegistry { return null; } - String[] requestedPermissions = new String[pkg.requestedPermissions.size()]; - pkg.requestedPermissions.toArray(requestedPermissions); + String[] requestedPermissions = new String[pkg.getRequestedPermissions().size()]; + pkg.getRequestedPermissions().toArray(requestedPermissions); Set<String> permissions = ps.getPermissionsState().getPermissions(userId); String[] grantedPermissions = new String[permissions.size()]; permissions.toArray(grantedPermissions); + // TODO(b/135203078): This may be broken due to inner mutability problems that were broken + // as part of moving to PackageInfoUtils. Flags couldn't be determined. + ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(ps.pkg, 0, + ps.readUserState(userId), userId); if (addApplicationInfo) { - return new InstantAppInfo(pkg.applicationInfo, + return new InstantAppInfo(appInfo, requestedPermissions, grantedPermissions); } else { - return new InstantAppInfo(pkg.applicationInfo.packageName, - pkg.applicationInfo.loadLabel(mService.mContext.getPackageManager()), + return new InstantAppInfo(appInfo.packageName, + appInfo.loadLabel(mService.mContext.getPackageManager()), requestedPermissions, grantedPermissions); } } @@ -887,10 +902,10 @@ class InstantAppRegistry { return uninstalledApps; } - private void propagateInstantAppPermissionsIfNeeded(@NonNull PackageParser.Package pkg, + private void propagateInstantAppPermissionsIfNeeded(@NonNull AndroidPackage pkg, @UserIdInt int userId) { InstantAppInfo appInfo = peekOrParseUninstalledInstantAppInfo( - pkg.packageName, userId); + pkg.getPackageName(), userId); if (appInfo == null) { return; } @@ -902,8 +917,10 @@ class InstantAppRegistry { for (String grantedPermission : appInfo.getGrantedPermissions()) { final boolean propagatePermission = mService.mSettings.canPropagatePermissionToInstantApp(grantedPermission); - if (propagatePermission && pkg.requestedPermissions.contains(grantedPermission)) { - mService.grantRuntimePermission(pkg.packageName, grantedPermission, userId); + if (propagatePermission && pkg.getRequestedPermissions().contains( + grantedPermission)) { + mService.grantRuntimePermission(pkg.getPackageName(), grantedPermission, + userId); } } } finally { @@ -1188,18 +1205,19 @@ class InstantAppRegistry { super(looper); } - public void schedulePersistLPw(@UserIdInt int userId, @NonNull PackageParser.Package pkg, + public void schedulePersistLPw(@UserIdInt int userId, @NonNull AndroidPackage pkg, @NonNull byte[] cookie) { // Before we used only the first signature to compute the SHA 256 but some // apps could be singed by multiple certs and the cert order is undefined. // We prefer the modern computation procedure where all certs are taken // into account and delete the file derived via the legacy hash computation. - File newCookieFile = computeInstantCookieFile(pkg.packageName, - PackageUtils.computeSignaturesSha256Digest(pkg.mSigningDetails.signatures), userId); - if (!pkg.mSigningDetails.hasSignatures()) { + File newCookieFile = computeInstantCookieFile(pkg.getPackageName(), + PackageUtils.computeSignaturesSha256Digest(pkg.getSigningDetails().signatures), + userId); + if (!pkg.getSigningDetails().hasSignatures()) { Slog.wtf(LOG_TAG, "Parsed Instant App contains no valid signatures!"); } - File oldCookieFile = peekInstantCookieFile(pkg.packageName, userId); + File oldCookieFile = peekInstantCookieFile(pkg.getPackageName(), userId); if (oldCookieFile != null && !newCookieFile.equals(oldCookieFile)) { oldCookieFile.delete(); } @@ -1209,12 +1227,12 @@ class InstantAppRegistry { PERSIST_COOKIE_DELAY_MILLIS); } - public @Nullable byte[] getPendingPersistCookieLPr(@NonNull PackageParser.Package pkg, + public @Nullable byte[] getPendingPersistCookieLPr(@NonNull AndroidPackage pkg, @UserIdInt int userId) { ArrayMap<String, SomeArgs> pendingWorkForUser = mPendingPersistCookies.get(userId); if (pendingWorkForUser != null) { - SomeArgs state = pendingWorkForUser.get(pkg.packageName); + SomeArgs state = pendingWorkForUser.get(pkg.getPackageName()); if (state != null) { return (byte[]) state.arg1; } @@ -1222,7 +1240,7 @@ class InstantAppRegistry { return null; } - public void cancelPendingPersistLPw(@NonNull PackageParser.Package pkg, + public void cancelPendingPersistLPw(@NonNull AndroidPackage pkg, @UserIdInt int userId) { removeMessages(userId, pkg); SomeArgs state = removePendingPersistCookieLPr(pkg, userId); @@ -1232,7 +1250,7 @@ class InstantAppRegistry { } private void addPendingPersistCookieLPw(@UserIdInt int userId, - @NonNull PackageParser.Package pkg, @NonNull byte[] cookie, + @NonNull AndroidPackage pkg, @NonNull byte[] cookie, @NonNull File cookieFile) { ArrayMap<String, SomeArgs> pendingWorkForUser = mPendingPersistCookies.get(userId); @@ -1243,16 +1261,16 @@ class InstantAppRegistry { SomeArgs args = SomeArgs.obtain(); args.arg1 = cookie; args.arg2 = cookieFile; - pendingWorkForUser.put(pkg.packageName, args); + pendingWorkForUser.put(pkg.getPackageName(), args); } - private SomeArgs removePendingPersistCookieLPr(@NonNull PackageParser.Package pkg, + private SomeArgs removePendingPersistCookieLPr(@NonNull AndroidPackage pkg, @UserIdInt int userId) { ArrayMap<String, SomeArgs> pendingWorkForUser = mPendingPersistCookies.get(userId); SomeArgs state = null; if (pendingWorkForUser != null) { - state = pendingWorkForUser.remove(pkg.packageName); + state = pendingWorkForUser.remove(pkg.getPackageName()); if (pendingWorkForUser.isEmpty()) { mPendingPersistCookies.remove(userId); } @@ -1263,7 +1281,7 @@ class InstantAppRegistry { @Override public void handleMessage(Message message) { int userId = message.what; - PackageParser.Package pkg = (PackageParser.Package) message.obj; + AndroidPackage pkg = (AndroidPackage) message.obj; SomeArgs state = removePendingPersistCookieLPr(pkg, userId); if (state == null) { return; @@ -1271,7 +1289,7 @@ class InstantAppRegistry { byte[] cookie = (byte[]) state.arg1; File cookieFile = (File) state.arg2; state.recycle(); - persistInstantApplicationCookie(cookie, pkg.packageName, cookieFile, userId); + persistInstantApplicationCookie(cookie, pkg.getPackageName(), cookieFile, userId); } } } diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java index ec48713b0874..0a065eba4309 100644 --- a/services/core/java/com/android/server/pm/InstructionSets.java +++ b/services/core/java/com/android/server/pm/InstructionSets.java @@ -16,7 +16,7 @@ package com.android.server.pm; -import android.content.pm.ApplicationInfo; +import android.content.pm.parsing.AndroidPackage; import android.os.Build; import android.os.SystemProperties; import android.text.TextUtils; @@ -35,30 +35,16 @@ import java.util.List; public class InstructionSets { private static final String PREFERRED_INSTRUCTION_SET = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); - public static String[] getAppDexInstructionSets(ApplicationInfo info) { - if (info.primaryCpuAbi != null) { - if (info.secondaryCpuAbi != null) { - return new String[] { - VMRuntime.getInstructionSet(info.primaryCpuAbi), - VMRuntime.getInstructionSet(info.secondaryCpuAbi) }; - } else { - return new String[] { - VMRuntime.getInstructionSet(info.primaryCpuAbi) }; - } - } - return new String[] { getPreferredInstructionSet() }; - } - - public static String[] getAppDexInstructionSets(PackageSetting ps) { - if (ps.primaryCpuAbiString != null) { - if (ps.secondaryCpuAbiString != null) { + public static String[] getAppDexInstructionSets(String primaryCpuAbi, String secondaryCpuAbi) { + if (primaryCpuAbi != null) { + if (secondaryCpuAbi != null) { return new String[] { - VMRuntime.getInstructionSet(ps.primaryCpuAbiString), - VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) }; + VMRuntime.getInstructionSet(primaryCpuAbi), + VMRuntime.getInstructionSet(secondaryCpuAbi) }; } else { return new String[] { - VMRuntime.getInstructionSet(ps.primaryCpuAbiString) }; + VMRuntime.getInstructionSet(primaryCpuAbi) }; } } @@ -124,4 +110,12 @@ public class InstructionSets { return VMRuntime.getInstructionSet(abis.primary); } + public static String getPrimaryInstructionSet(AndroidPackage pkg) { + if (pkg.getPrimaryCpuAbi() == null) { + return getPreferredInstructionSet(); + } + + return VMRuntime.getInstructionSet(pkg.getPrimaryCpuAbi()); + } + } diff --git a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java index a4e9d103b6da..c97d85df00ab 100644 --- a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java +++ b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java @@ -17,7 +17,7 @@ package com.android.server.pm; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; +import android.content.pm.parsing.ComponentParseUtils; import android.util.ArraySet; import android.util.Slog; @@ -35,7 +35,7 @@ public class IntentFilterVerificationState { private int mState; - private ArrayList<PackageParser.ActivityIntentInfo> mFilters = new ArrayList<>(); + private ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> mFilters = new ArrayList<>(); private ArraySet<String> mHosts = new ArraySet<>(); private int mUserId; @@ -66,7 +66,7 @@ public class IntentFilterVerificationState { setState(STATE_VERIFICATION_PENDING); } - public ArrayList<PackageParser.ActivityIntentInfo> getFilters() { + public ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> getFilters() { return mFilters; } @@ -123,7 +123,7 @@ public class IntentFilterVerificationState { return false; } - public void addFilter(PackageParser.ActivityIntentInfo filter) { + public void addFilter(ComponentParseUtils.ParsedActivityIntentInfo filter) { mFilters.add(filter); mHosts.addAll(filter.getHostsList()); } diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java index 93d3b77511bc..70c0f8d98447 100644 --- a/services/core/java/com/android/server/pm/KeySetManagerService.java +++ b/services/core/java/com/android/server/pm/KeySetManagerService.java @@ -20,23 +20,26 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static com.android.server.pm.PackageManagerService.SCAN_INITIAL; -import com.android.internal.util.Preconditions; import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Base64; -import android.util.Slog; import android.util.LongSparseArray; +import android.util.Slog; -import java.io.IOException; -import java.io.PrintWriter; -import java.security.PublicKey; -import java.util.Set; +import com.android.internal.util.Preconditions; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import java.io.IOException; +import java.io.PrintWriter; +import java.security.PublicKey; +import java.util.Map; +import java.util.Set; + /* * Manages system-wide KeySet state. */ @@ -182,33 +185,31 @@ public class KeySetManagerService { * * Returns true if the package can safely be added to the keyset metadata. */ - public void assertScannedPackageValid(PackageParser.Package pkg) + public void assertScannedPackageValid(AndroidPackage pkg) throws PackageManagerException { - if (pkg == null || pkg.packageName == null) { + if (pkg == null || pkg.getPackageName() == null) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Passed invalid package to keyset validation."); } - ArraySet<PublicKey> signingKeys = pkg.mSigningDetails.publicKeys; + ArraySet<PublicKey> signingKeys = pkg.getSigningDetails().publicKeys; if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Package has invalid signing-key-set."); } - ArrayMap<String, ArraySet<PublicKey>> definedMapping = pkg.mKeySetMapping; + Map<String, ArraySet<PublicKey>> definedMapping = pkg.getKeySetMapping(); if (definedMapping != null) { if (definedMapping.containsKey(null) || definedMapping.containsValue(null)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Package has null defined key set."); } - int defMapSize = definedMapping.size(); - for (int i = 0; i < defMapSize; i++) { - if (!(definedMapping.valueAt(i).size() > 0) - || definedMapping.valueAt(i).contains(null)) { + for (ArraySet<PublicKey> value : definedMapping.values()) { + if (!(value.size() > 0) || value.contains(null)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Package has null/no public keys for defined key-sets."); } } } - ArraySet<String> upgradeAliases = pkg.mUpgradeKeySets; + Set<String> upgradeAliases = pkg.getUpgradeKeySets(); if (upgradeAliases != null) { if (definedMapping == null || !(definedMapping.keySet().containsAll(upgradeAliases))) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, @@ -217,17 +218,17 @@ public class KeySetManagerService { } } - public void addScannedPackageLPw(PackageParser.Package pkg) { + public void addScannedPackageLPw(AndroidPackage pkg) { Preconditions.checkNotNull(pkg, "Attempted to add null pkg to ksms."); - Preconditions.checkNotNull(pkg.packageName, "Attempted to add null pkg to ksms."); - PackageSetting ps = mPackages.get(pkg.packageName); - Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName + Preconditions.checkNotNull(pkg.getPackageName(), "Attempted to add null pkg to ksms."); + PackageSetting ps = mPackages.get(pkg.getPackageName()); + Preconditions.checkNotNull(ps, "pkg: " + pkg.getPackageName() + "does not have a corresponding entry in mPackages."); - addSigningKeySetToPackageLPw(ps, pkg.mSigningDetails.publicKeys); - if (pkg.mKeySetMapping != null) { - addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping); - if (pkg.mUpgradeKeySets != null) { - addUpgradeKeySetsToPackageLPw(ps, pkg.mUpgradeKeySets); + addSigningKeySetToPackageLPw(ps, pkg.getSigningDetails().publicKeys); + if (pkg.getKeySetMapping() != null) { + addDefinedKeySetsToPackageLPw(ps, pkg.getKeySetMapping()); + if (pkg.getUpgradeKeySets() != null) { + addUpgradeKeySetsToPackageLPw(ps, pkg.getUpgradeKeySets()); } } } @@ -280,15 +281,14 @@ public class KeySetManagerService { * Remove any KeySets the package no longer defines. */ void addDefinedKeySetsToPackageLPw(PackageSetting pkg, - ArrayMap<String, ArraySet<PublicKey>> definedMapping) { + Map<String, ArraySet<PublicKey>> definedMapping) { ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases(); /* add all of the newly defined KeySets */ - ArrayMap<String, Long> newKeySetAliases = new ArrayMap<String, Long>(); - final int defMapSize = definedMapping.size(); - for (int i = 0; i < defMapSize; i++) { - String alias = definedMapping.keyAt(i); - ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i); + Map<String, Long> newKeySetAliases = new ArrayMap<>(); + for (Map.Entry<String, ArraySet<PublicKey>> entry : definedMapping.entrySet()) { + String alias = entry.getKey(); + ArraySet<PublicKey> pubKeys = entry.getValue(); if (alias != null && pubKeys != null && pubKeys.size() > 0) { KeySetHandle ks = addKeySetLPw(pubKeys); newKeySetAliases.put(alias, ks.getId()); @@ -313,12 +313,10 @@ public class KeySetManagerService { * after all of the defined KeySets have been added. */ void addUpgradeKeySetsToPackageLPw(PackageSetting pkg, - ArraySet<String> upgradeAliases) { - final int uaSize = upgradeAliases.size(); - for (int i = 0; i < uaSize; i++) { - pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i)); + Set<String> upgradeAliases) { + for (String upgradeAlias : upgradeAliases) { + pkg.keySetData.addUpgradeKeySet(upgradeAlias); } - return; } /** @@ -364,14 +362,14 @@ public class KeySetManagerService { return true; } - public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS, - PackageParser.Package newPkg) { + public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS, AndroidPackage pkg) { // Upgrade keysets are being used. Determine if new package has a superset of the // required keys. long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets(); for (int i = 0; i < upgradeKeySets.length; i++) { Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]); - if (upgradeSet != null && newPkg.mSigningDetails.publicKeys.containsAll(upgradeSet)) { + if (upgradeSet != null + && pkg.getSigningDetails().publicKeys.containsAll(upgradeSet)) { return true; } } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index f7fd1b2ddb37..673e265787f3 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -40,13 +40,13 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; -import android.content.pm.PackageParser; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutServiceInternal; import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener; import android.content.pm.UserInfo; +import android.content.pm.parsing.AndroidPackage; import android.graphics.Rect; import android.net.Uri; import android.os.Binder; @@ -447,7 +447,7 @@ public class LauncherAppsService extends SystemService { } final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); - final PackageParser.Package pkg = pmInt.getPackage(appInfo.packageName); + final AndroidPackage pkg = pmInt.getPackage(appInfo.packageName); if (pkg == null) { // Should not happen, but we shouldn't be failing if it does return false; @@ -458,8 +458,8 @@ public class LauncherAppsService extends SystemService { appInfo.packageName); } - private boolean requestsPermissions(@NonNull PackageParser.Package pkg) { - return !ArrayUtils.isEmpty(pkg.requestedPermissions); + private boolean requestsPermissions(@NonNull AndroidPackage pkg) { + return !ArrayUtils.isEmpty(pkg.getRequestedPermissions()); } private boolean hasDefaultEnableLauncherActivity(@NonNull String packageName) { diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index d49ecdda679d..ae7a4a7b81f5 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -22,7 +22,7 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import android.annotation.Nullable; import android.content.Context; import android.content.pm.IOtaDexopt; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.os.Environment; import android.os.RemoteException; import android.os.ResultReceiver; @@ -118,8 +118,8 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (mDexoptCommands != null) { throw new IllegalStateException("already called prepare()"); } - final List<PackageParser.Package> important; - final List<PackageParser.Package> others; + final List<AndroidPackage> important; + final List<AndroidPackage> others; synchronized (mPackageManagerService.mLock) { // Important: the packages we need to run with ab-ota compiler-reason. important = PackageManagerServiceUtils.getPackagesForDexopt( @@ -133,12 +133,12 @@ public class OtaDexoptService extends IOtaDexopt.Stub { mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2); } - for (PackageParser.Package p : important) { + for (AndroidPackage p : important) { mDexoptCommands.addAll(generatePackageDexopts(p, PackageManagerService.REASON_AB_OTA)); } - for (PackageParser.Package p : others) { + for (AndroidPackage p : others) { // We assume here that there are no core apps left. - if (p.coreApp) { + if (p.isCoreApp()) { throw new IllegalStateException("Found a core app that's not important"); } mDexoptCommands.addAll( @@ -150,8 +150,8 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (spaceAvailable < BULK_DELETE_THRESHOLD) { Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: " + PackageManagerServiceUtils.packagesToString(others)); - for (PackageParser.Package pkg : others) { - mPackageManagerService.deleteOatArtifactsOfPackage(pkg.packageName); + for (AndroidPackage pkg : others) { + mPackageManagerService.deleteOatArtifactsOfPackage(pkg.getPackageName()); } } long spaceAvailableNow = getAvailableSpace(); @@ -161,15 +161,15 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (DEBUG_DEXOPT) { try { // Output some data about the packages. - PackageParser.Package lastUsed = Collections.max(important, + AndroidPackage lastUsed = Collections.max(important, (pkg1, pkg2) -> Long.compare( pkg1.getLatestForegroundPackageUseTimeInMills(), pkg2.getLatestForegroundPackageUseTimeInMills())); Log.d(TAG, "A/B OTA: lastUsed time = " + lastUsed.getLatestForegroundPackageUseTimeInMills()); Log.d(TAG, "A/B OTA: deprioritized packages:"); - for (PackageParser.Package pkg : others) { - Log.d(TAG, " " + pkg.packageName + " - " + for (AndroidPackage pkg : others) { + Log.d(TAG, " " + pkg.getPackageName() + " - " + pkg.getLatestForegroundPackageUseTimeInMills()); } } catch (Exception ignored) { @@ -262,7 +262,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub { /** * Generate all dexopt commands for the given package. */ - private synchronized List<String> generatePackageDexopts(PackageParser.Package pkg, + private synchronized List<String> generatePackageDexopts(AndroidPackage pkg, int compilationReason) { // Intercept and collect dexopt requests final List<String> commands = new ArrayList<String>(); @@ -336,8 +336,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub { optimizer.performDexOpt(pkg, null /* ISAs */, null /* CompilerStats.PackageStats */, - mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(pkg.packageName), - new DexoptOptions(pkg.packageName, compilationReason, + mPackageManagerService.getDexManager().getPackageUseInfoOrDefault( + pkg.getPackageName()), + new DexoptOptions(pkg.getPackageName(), compilationReason, DexoptOptions.DEXOPT_BOOT_COMPLETE)); return commands; @@ -359,10 +360,10 @@ public class OtaDexoptService extends IOtaDexopt.Stub { } // Look into all packages. - Collection<PackageParser.Package> pkgs = mPackageManagerService.getPackages(); + Collection<AndroidPackage> pkgs = mPackageManagerService.getPackages(); int packagePaths = 0; int pathsSuccessful = 0; - for (PackageParser.Package pkg : pkgs) { + for (AndroidPackage pkg : pkgs) { if (pkg == null) { continue; } @@ -371,27 +372,28 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (!PackageDexOptimizer.canOptimizePackage(pkg)) { continue; } - if (pkg.codePath == null) { + if (pkg.getCodePath() == null) { Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath"); continue; } // If the path is in /system, /vendor, /product or /system_ext, ignore. It will // have been ota-dexopted into /data/ota and moved into the dalvik-cache already. - if (pkg.codePath.startsWith("/system") - || pkg.codePath.startsWith("/vendor") - || pkg.codePath.startsWith("/product") - || pkg.codePath.startsWith("/system_ext")) { + if (pkg.getCodePath().startsWith("/system") + || pkg.getCodePath().startsWith("/vendor") + || pkg.getCodePath().startsWith("/product") + || pkg.getCodePath().startsWith("/system_ext")) { continue; } - final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo); + final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), + pkg.getSecondaryCpuAbi()); final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly(); final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); for (String dexCodeInstructionSet : dexCodeInstructionSets) { for (String path : paths) { - String oatDir = PackageDexOptimizer.getOatDir(new File(pkg.codePath)). - getAbsolutePath(); + String oatDir = PackageDexOptimizer.getOatDir( + new File(pkg.getCodePath())).getAbsolutePath(); // TODO: Check first whether there is an artifact, to save the roundtrip time. diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java index c21d0cf54d91..d7c161cc1a86 100644 --- a/services/core/java/com/android/server/pm/PackageAbiHelper.java +++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java @@ -17,7 +17,8 @@ package com.android.server.pm; import android.annotation.Nullable; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsedPackage; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; @@ -25,21 +26,21 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.File; import java.util.Set; +// TODO: Move to .parsing sub-package @VisibleForTesting public interface PackageAbiHelper { /** * Derive and get the location of native libraries for the given package, * which varies depending on where and how the package was installed. */ - NativeLibraryPaths getNativeLibraryPaths( - PackageParser.Package pkg, File appLib32InstallDir); + NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, File appLib32InstallDir); /** * Calculate the abis for a bundled app. These can uniquely be determined from the contents of * the system partition, i.e whether it contains 64 or 32 bit shared libraries etc. We do not * validate any of this information, and instead assume that the system was built sensibly. */ - Abis getBundledAppAbis(PackageParser.Package pkg); + Abis getBundledAppAbis(AndroidPackage pkg); /** * Derive the ABI of a non-system package located at {@code pkg}. This information @@ -48,7 +49,7 @@ public interface PackageAbiHelper { * If {@code extractLibs} is true, native libraries are extracted from the app if required. */ Pair<Abis, NativeLibraryPaths> derivePackageAbi( - PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs) + AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs) throws PackageManagerException; /** @@ -69,11 +70,11 @@ public interface PackageAbiHelper { */ @Nullable String getAdjustedAbiForSharedUser( - Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage); + Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage); /** * The native library paths and related properties that should be set on a - * {@link android.content.pm.PackageParser.Package}. + * {@link ParsedPackage}. */ final class NativeLibraryPaths { public final String nativeLibraryRootDir; @@ -91,11 +92,11 @@ public interface PackageAbiHelper { this.secondaryNativeLibraryDir = secondaryNativeLibraryDir; } - public void applyTo(PackageParser.Package pkg) { - pkg.applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir; - pkg.applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; - pkg.applicationInfo.nativeLibraryDir = nativeLibraryDir; - pkg.applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir; + public void applyTo(ParsedPackage pkg) { + pkg.setNativeLibraryRootDir(nativeLibraryRootDir) + .setNativeLibraryRootRequiresIsa(nativeLibraryRootRequiresIsa) + .setNativeLibraryDir(nativeLibraryDir) + .setSecondaryNativeLibraryDir(secondaryNativeLibraryDir); } } @@ -112,13 +113,13 @@ public interface PackageAbiHelper { this.secondary = secondary; } - Abis(PackageParser.Package pkg) { - this(pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi); + Abis(AndroidPackage pkg) { + this(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi()); } - public void applyTo(PackageParser.Package pkg) { - pkg.applicationInfo.primaryCpuAbi = primary; - pkg.applicationInfo.secondaryCpuAbi = secondary; + public void applyTo(ParsedPackage pkg) { + pkg.setPrimaryCpuAbi(primary) + .setSecondaryCpuAbi(secondary); } public void applyTo(PackageSetting pkgSetting) { // pkgSetting might be null during rescan following uninstall of updates diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java index 7e478009b6b3..e550bae7484b 100644 --- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java +++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java @@ -29,7 +29,7 @@ import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet; import android.annotation.Nullable; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.os.Build; import android.os.Environment; import android.os.FileUtils; @@ -132,10 +132,10 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { @Override public NativeLibraryPaths getNativeLibraryPaths( - PackageParser.Package pkg, File appLib32InstallDir) { - return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.codePath, - pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(), - pkg.applicationInfo.isUpdatedSystemApp()); + AndroidPackage pkg, File appLib32InstallDir) { + return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.getCodePath(), + pkg.getBaseCodePath(), pkg.isSystemApp(), + pkg.isUpdatedSystemApp()); } private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis, @@ -202,12 +202,12 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { } @Override - public Abis getBundledAppAbis(PackageParser.Package pkg) { - final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath()); + public Abis getBundledAppAbis(AndroidPackage pkg) { + final String apkName = deriveCodePathName(pkg.getCodePath()); // If "/system/lib64/apkname" exists, assume that is the per-package // native library directory to use; otherwise use "/system/lib/apkname". - final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir); + final String apkRoot = calculateBundledApkRoot(pkg.getBaseCodePath()); final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName); return abis; } @@ -220,8 +220,8 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { * {@code /oem} under which system libraries are installed. * @param apkName the name of the installed package. */ - private Abis getBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) { - final File codeFile = new File(pkg.codePath); + private Abis getBundledAppAbi(AndroidPackage pkg, String apkRoot, String apkName) { + final File codeFile = new File(pkg.getCodePath()); final boolean has64BitLibs; final boolean has32BitLibs; @@ -273,7 +273,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { // ABI that's higher on the list, i.e, a device that's configured to prefer // 64 bit apps will see a 64 bit primary ABI, - if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) == 0) { Slog.e(PackageManagerService.TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch."); } @@ -294,14 +294,14 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { @Override public Pair<Abis, NativeLibraryPaths> derivePackageAbi( - PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs) + AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs) throws PackageManagerException { // Give ourselves some initial paths; we'll come back for another // pass once we've determined ABI below. final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(new Abis(pkg), - PackageManagerService.sAppLib32InstallDir, pkg.codePath, - pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(), - pkg.applicationInfo.isUpdatedSystemApp()); + PackageManagerService.sAppLib32InstallDir, pkg.getCodePath(), + pkg.getBaseCodePath(), pkg.isSystemApp(), + pkg.isUpdatedSystemApp()); // We shouldn't attempt to extract libs from system app when it was not updated. if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) { @@ -310,7 +310,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir; final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa; - final boolean onIncremental = isIncrementalPath(pkg.codePath); + final boolean onIncremental = isIncrementalPath(pkg.getCodePath()); String primaryCpuAbi = null; String secondaryCpuAbi = null; @@ -329,12 +329,13 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { // Null out the abis so that they can be recalculated. primaryCpuAbi = null; secondaryCpuAbi = null; - if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0) { // Warn if we've set an abiOverride for multi-lib packages.. // By definition, we need to copy both 32 and 64 bit libraries for // such packages. - if (pkg.cpuAbiOverride != null - && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) { + if (pkg.getCpuAbiOverride() != null + && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals( + pkg.getCpuAbiOverride())) { Slog.w(PackageManagerService.TAG, "Ignoring abiOverride for multi arch application."); } @@ -409,7 +410,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { if (abi32 >= 0) { final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32]; if (abi64 >= 0) { - if (pkg.use32bitAbi) { + if (pkg.isUse32BitAbi()) { secondaryCpuAbi = primaryCpuAbi; primaryCpuAbi = abi; } else { @@ -482,9 +483,9 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi); return new Pair<>(abis, getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir, - pkg.codePath, pkg.applicationInfo.sourceDir, - pkg.applicationInfo.isSystemApp(), - pkg.applicationInfo.isUpdatedSystemApp())); + pkg.getCodePath(), pkg.getBaseCodePath(), + pkg.isSystemApp(), + pkg.isUpdatedSystemApp())); } /** @@ -503,11 +504,11 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { @Override @Nullable public String getAdjustedAbiForSharedUser( - Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) { + Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage) { String requiredInstructionSet = null; - if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) { + if (scannedPackage != null && scannedPackage.getPrimaryCpuAbi() != null) { requiredInstructionSet = VMRuntime.getInstructionSet( - scannedPackage.applicationInfo.primaryCpuAbi); + scannedPackage.getPrimaryCpuAbi()); } PackageSetting requirer = null; @@ -516,7 +517,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { // when scannedPackage is an update of an existing package. Without this check, // we will never be able to change the ABI of any package belonging to a shared // user, even if it's compatible with other packages. - if (scannedPackage != null && scannedPackage.packageName.equals(ps.name)) { + if (scannedPackage != null && scannedPackage.getPackageName().equals(ps.name)) { continue; } if (ps.primaryCpuAbiString == null) { @@ -554,7 +555,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { } else { // requirer == null implies that we're updating all ABIs in the set to // match scannedPackage. - adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi; + adjustedAbi = scannedPackage.getPrimaryCpuAbi(); } return adjustedAbi; } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 4f7c8c8da4a9..2b422211077b 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -41,10 +41,10 @@ import static dalvik.system.DexFile.isProfileGuidedCompilerFilter; import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageParser; import android.content.pm.SharedLibraryInfo; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; +import android.content.pm.parsing.AndroidPackage; import android.os.FileUtils; import android.os.PowerManager; import android.os.SystemClock; @@ -53,6 +53,7 @@ import android.os.UserHandle; import android.os.WorkSource; import android.util.Log; import android.util.Slog; +import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; @@ -109,9 +110,9 @@ public class PackageDexOptimizer { this.mSystemReady = from.mSystemReady; } - static boolean canOptimizePackage(PackageParser.Package pkg) { + static boolean canOptimizePackage(AndroidPackage pkg) { // We do not dexopt a package with no code. - if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) == 0) { return false; } @@ -125,18 +126,18 @@ public class PackageDexOptimizer { * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are * synchronized on {@link #mInstallLock}. */ - int performDexOpt(PackageParser.Package pkg, + int performDexOpt(AndroidPackage pkg, String[] instructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) { - if (pkg.applicationInfo.uid == -1) { - throw new IllegalArgumentException("Dexopt for " + pkg.packageName + if (pkg.getUid() == -1) { + throw new IllegalArgumentException("Dexopt for " + pkg.getPackageName() + " has invalid uid."); } if (!canOptimizePackage(pkg)) { return DEX_OPT_SKIPPED; } synchronized (mInstallLock) { - final long acquireTime = acquireWakeLockLI(pkg.applicationInfo.uid); + final long acquireTime = acquireWakeLockLI(pkg.getUid()); try { return performDexOptLI(pkg, instructionSets, packageStats, packageUseInfo, options); @@ -151,19 +152,20 @@ public class PackageDexOptimizer { * It assumes the install lock is held. */ @GuardedBy("mInstallLock") - private int performDexOptLI(PackageParser.Package pkg, + private int performDexOptLI(AndroidPackage pkg, String[] targetInstructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) { - final List<SharedLibraryInfo> sharedLibraries = pkg.usesLibraryInfos; + final List<SharedLibraryInfo> sharedLibraries = pkg.getUsesLibraryInfos(); final String[] instructionSets = targetInstructionSets != null ? - targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo); + targetInstructionSets : getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), + pkg.getSecondaryCpuAbi()); final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); final List<String> paths = pkg.getAllCodePaths(); - int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + int sharedGid = UserHandle.getSharedAppGid(pkg.getUid()); if (sharedGid == -1) { - Slog.wtf(TAG, "Well this is awkward; package " + pkg.applicationInfo.name + " had UID " - + pkg.applicationInfo.uid, new Throwable()); + Slog.wtf(TAG, "Well this is awkward; package " + pkg.getAppInfoName() + " had UID " + + pkg.getUid(), new Throwable()); sharedGid = android.os.Process.NOBODY_UID; } @@ -171,21 +173,21 @@ public class PackageDexOptimizer { // For each code path in the package, this array contains the class loader context that // needs to be passed to dexopt in order to ensure correct optimizations. boolean[] pathsWithCode = new boolean[paths.size()]; - pathsWithCode[0] = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0; + pathsWithCode[0] = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0; for (int i = 1; i < paths.size(); i++) { - pathsWithCode[i] = (pkg.splitFlags[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0; + pathsWithCode[i] = (pkg.getSplitFlags()[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0; } String[] classLoaderContexts = DexoptUtils.getClassLoaderContexts( - pkg.applicationInfo, sharedLibraries, pathsWithCode); + pkg, sharedLibraries, pathsWithCode); // Sanity check that we do not call dexopt with inconsistent data. if (paths.size() != classLoaderContexts.length) { - String[] splitCodePaths = pkg.applicationInfo.getSplitCodePaths(); + String[] splitCodePaths = pkg.getSplitCodePaths(); throw new IllegalStateException("Inconsistent information " + "between PackageParser.Package and its ApplicationInfo. " + "pkg.getAllCodePaths=" + paths - + " pkg.applicationInfo.getBaseCodePath=" + pkg.applicationInfo.getBaseCodePath() - + " pkg.applicationInfo.getSplitCodePaths=" + + " pkg.getBaseCodePath=" + pkg.getBaseCodePath() + + " pkg.getSplitCodePaths=" + (splitCodePaths == null ? "null" : Arrays.toString(splitCodePaths))); } @@ -211,7 +213,8 @@ public class PackageDexOptimizer { } } - String profileName = ArtManager.getProfileName(i == 0 ? null : pkg.splitNames[i - 1]); + String profileName = ArtManager.getProfileName( + i == 0 ? null : pkg.getSplitNames()[i - 1]); String dexMetadataPath = null; if (options.isDexoptInstallWithDexMetadata()) { @@ -222,7 +225,7 @@ public class PackageDexOptimizer { final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary() || packageUseInfo.isUsedByOtherApps(path); - final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo, + final String compilerFilter = getRealCompilerFilter(pkg, options.getCompilerFilter(), isUsedByOtherApps); final boolean profileUpdated = options.isCheckForProfileUpdates() && isProfileUpdated(pkg, sharedGid, profileName, compilerFilter); @@ -257,7 +260,7 @@ public class PackageDexOptimizer { * DEX_OPT_SKIPPED if the path does not need to be deopt-ed. */ @GuardedBy("mInstallLock") - private int dexOptPath(PackageParser.Package pkg, String path, String isa, + private int dexOptPath(AndroidPackage pkg, String path, String isa, String compilerFilter, boolean profileUpdated, String classLoaderContext, int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade, String profileName, String dexMetadataPath, int compilationReason) { @@ -270,7 +273,7 @@ public class PackageDexOptimizer { String oatDir = getPackageOatDirIfSupported(pkg); Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path - + " pkg=" + pkg.applicationInfo.packageName + " isa=" + isa + + " pkg=" + pkg.getAppInfoPackageName() + " isa=" + isa + " dexoptFlags=" + printDexoptFlags(dexoptFlags) + " targetFilter=" + compilerFilter + " oatDir=" + oatDir + " classLoaderContext=" + classLoaderContext); @@ -281,9 +284,9 @@ public class PackageDexOptimizer { // TODO: Consider adding 2 different APIs for primary and secondary dexopt. // installd only uses downgrade flag for secondary dex files and ignores it for // primary dex files. - mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags, - compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo, - false /* downgrade*/, pkg.applicationInfo.targetSdkVersion, + mInstaller.dexopt(path, uid, pkg.getPackageName(), isa, dexoptNeeded, oatDir, + dexoptFlags, compilerFilter, pkg.getVolumeUuid(), classLoaderContext, + pkg.getSeInfo(), false /* downgrade*/, pkg.getTargetSdkVersion(), profileName, dexMetadataPath, getAugmentedReasonName(compilationReason, dexMetadataPath != null)); @@ -446,9 +449,10 @@ public class PackageDexOptimizer { /** * Dumps the dexopt state of the given package {@code pkg} to the given {@code PrintWriter}. */ - void dumpDexoptState(IndentingPrintWriter pw, PackageParser.Package pkg, + void dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg, PackageDexUsage.PackageUseInfo useInfo) { - final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo); + final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), + pkg.getSecondaryCpuAbi()); final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly(); @@ -504,7 +508,7 @@ public class PackageDexOptimizer { // When an app or priv app is configured to run out of box, only verify it. if (info.isEmbeddedDexUsed() || (info.isPrivilegedApp() - && DexManager.isPackageSelectedToRunOob(info.packageName))) { + && DexManager.isPackageSelectedToRunOob(info.packageName))) { return "verify"; } @@ -535,12 +539,43 @@ public class PackageDexOptimizer { } /** - * Computes the dex flags that needs to be pass to installd for the given package and compiler - * filter. + * Returns the compiler filter that should be used to optimize the package code. + * The target filter will be updated if the package code is used by other apps + * or if it has the safe mode flag set. */ - private int getDexFlags(PackageParser.Package pkg, String compilerFilter, - DexoptOptions options) { - return getDexFlags(pkg.applicationInfo, compilerFilter, options); + private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter, + boolean isUsedByOtherApps) { + // When an app or priv app is configured to run out of box, only verify it. + if (pkg.isEmbeddedDexUsed() + || (pkg.isPrivileged() + && DexManager.isPackageSelectedToRunOob(pkg.getPackageName()))) { + return "verify"; + } + + // We force vmSafeMode on debuggable apps as well: + // - the runtime ignores their compiled code + // - they generally have lots of methods that could make the compiler used run + // out of memory (b/130828957) + // Note that forcing the compiler filter here applies to all compilations (even if they + // are done via adb shell commands). That's ok because right now the runtime will ignore + // the compiled code anyway. The alternative would have been to update either + // PackageDexOptimizer#canOptimizePackage or PackageManagerService#getOptimizablePackages + // but that would have the downside of possibly producing a big odex files which would + // be ignored anyway. + boolean vmSafeModeOrDebuggable = ((pkg.getFlags() & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0) + || ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0); + + if (vmSafeModeOrDebuggable) { + return getSafeModeCompilerFilter(targetCompilerFilter); + } + + if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) { + // If the dex files is used by other apps, apply the shared filter. + return PackageManagerServiceCompilerMapping.getCompilerFilterForReason( + PackageManagerService.REASON_SHARED); + } + + return targetCompilerFilter; } private boolean isAppImageEnabled() { @@ -548,7 +583,24 @@ public class PackageDexOptimizer { } private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) { - int flags = info.flags; + return getDexFlags(info.flags, info.getHiddenApiEnforcementPolicy(), + info.splitDependencies, info.requestsIsolatedSplitLoading(), compilerFilter, + options); + } + private int getDexFlags(AndroidPackage pkg, String compilerFilter, + DexoptOptions options) { + return getDexFlags(pkg.getFlags(), pkg.getHiddenApiEnforcementPolicy(), + pkg.getSplitDependencies(), pkg.requestsIsolatedSplitLoading(), compilerFilter, + options); + } + + /** + * Computes the dex flags that needs to be pass to installd for the given package and compiler + * filter. + */ + private int getDexFlags(int flags, int hiddenApiEnforcementPolicy, + SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading, + String compilerFilter, DexoptOptions options) { boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; // Profile guide compiled oat files should not be public unles they are based // on profiles from dex metadata archives. @@ -560,7 +612,9 @@ public class PackageDexOptimizer { // Some apps are executed with restrictions on hidden API usage. If this app is one // of them, pass a flag to dexopt to enable the same restrictions during compilation. // TODO we should pass the actual flag value to dexopt, rather than assuming blacklist - int hiddenApiFlag = info.getHiddenApiEnforcementPolicy() == HIDDEN_API_ENFORCEMENT_DISABLED + // TODO(b/135203078): This flag is no longer set as part of AndroidPackage + // and may not be preserved + int hiddenApiFlag = hiddenApiEnforcementPolicy == HIDDEN_API_ENFORCEMENT_DISABLED ? 0 : DEXOPT_ENABLE_HIDDEN_API_CHECKS; // Avoid generating CompactDex for modes that are latency critical. @@ -578,8 +632,8 @@ public class PackageDexOptimizer { // declare inter-split dependencies, then all the splits will be loaded in the base // apk class loader (in the order of their definition, otherwise disable app images // because they are unsupported for multiple class loaders. b/7269679 - boolean generateAppImage = isProfileGuidedFilter && (info.splitDependencies == null || - !info.requestsIsolatedSplitLoading()) && isAppImageEnabled(); + boolean generateAppImage = isProfileGuidedFilter && (splitDependencies == null || + !requestsIsolatedSplitLoading) && isAppImageEnabled(); int dexFlags = (isPublic ? DEXOPT_PUBLIC : 0) | (debuggable ? DEXOPT_DEBUGGABLE : 0) @@ -617,7 +671,7 @@ public class PackageDexOptimizer { * current profile and the reference profile will be merged and subsequent calls * may return a different result. */ - private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String profileName, + private boolean isProfileUpdated(AndroidPackage pkg, int uid, String profileName, String compilerFilter) { // Check if we are allowed to merge and if the compiler filter is profile guided. if (!isProfileGuidedCompilerFilter(compilerFilter)) { @@ -625,7 +679,7 @@ public class PackageDexOptimizer { } // Merge profiles. It returns whether or not there was an updated in the profile info. try { - return mInstaller.mergeProfiles(uid, pkg.packageName, profileName); + return mInstaller.mergeProfiles(uid, pkg.getPackageName(), profileName); } catch (InstallerException e) { Slog.w(TAG, "Failed to merge profiles", e); } @@ -645,11 +699,11 @@ public class PackageDexOptimizer { * not needed or unsupported for the package. */ @Nullable - private String getPackageOatDirIfSupported(PackageParser.Package pkg) { + private String getPackageOatDirIfSupported(AndroidPackage pkg) { if (!pkg.canHaveOatDir()) { return null; } - File codePath = new File(pkg.codePath); + File codePath = new File(pkg.getCodePath()); if (!codePath.isDirectory()) { return null; } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 883baf7886af..518ec5085a5e 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -66,6 +66,7 @@ import android.content.pm.PackageParser.ApkLite; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.dex.DexMetadataHelper; +import android.content.pm.parsing.ApkLiteParseUtils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Binder; @@ -1677,7 +1678,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { for (File addedFile : addedFiles) { final ApkLite apk; try { - apk = PackageParser.parseApkLite( + apk = ApkLiteParseUtils.parseApkLite( addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES); } catch (PackageParserException e) { throw PackageManagerException.from(e); @@ -1776,7 +1777,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { ApplicationInfo appInfo = pkgInfo.applicationInfo; try { existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0); - existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()), + existingBase = ApkLiteParseUtils.parseApkLite(new File(appInfo.getBaseCodePath()), PackageParser.PARSE_COLLECT_CERTIFICATES); } catch (PackageParserException e) { throw PackageManagerException.from(e); diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java index 031b5ce3d5b9..10685b06716f 100644 --- a/services/core/java/com/android/server/pm/PackageKeySetData.java +++ b/services/core/java/com/android/server/pm/PackageKeySetData.java @@ -20,6 +20,8 @@ import android.util.ArrayMap; import com.android.internal.util.ArrayUtils; +import java.util.Map; + public class PackageKeySetData { static final long KEYSET_UNASSIGNED = -1; @@ -90,16 +92,13 @@ public class PackageKeySetData { /* * Replace defined keysets with new ones. */ - protected void setAliases(ArrayMap<String, Long> newAliases) { + protected void setAliases(Map<String, Long> newAliases) { /* remove old aliases */ removeAllDefinedKeySets(); /* add new ones */ - final int newAliasSize = newAliases.size(); - for (int i = 0; i < newAliasSize; i++) { - mKeySetAliases.put(newAliases.keyAt(i), newAliases.valueAt(i));; - } + mKeySetAliases.putAll(newAliases); } protected void addDefinedKeySet(long ks, String alias) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 3d4247e761b5..ac102308d87b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -34,7 +34,6 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; -import static android.content.pm.PackageManager.DELETE_KEEP_DATA; import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT; @@ -160,7 +159,6 @@ import android.content.pm.InstrumentationInfo; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.KeySet; import android.content.pm.ModuleInfo; -import android.content.pm.PackageBackwardCompatibility; import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageInstaller; @@ -170,7 +168,6 @@ import android.content.pm.PackageManager.ModuleInfoFlags; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal.PackageListObserver; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.ActivityIntentInfo; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.ParseFlags; @@ -195,6 +192,19 @@ import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.IArtManager; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ApkParseUtils; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; +import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.PackageInfoUtils; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.library.PackageBackwardCompatibility; import android.content.res.Resources; import android.content.rollback.IRollbackManager; import android.database.ContentObserver; @@ -462,20 +472,19 @@ public class PackageManagerService extends IPackageManager.Stub static final int SCAN_REQUIRE_KNOWN = 1 << 7; static final int SCAN_MOVE = 1 << 8; static final int SCAN_INITIAL = 1 << 9; - static final int SCAN_CHECK_ONLY = 1 << 10; - static final int SCAN_DONT_KILL_APP = 1 << 11; - static final int SCAN_IGNORE_FROZEN = 1 << 12; - static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 13; - static final int SCAN_AS_INSTANT_APP = 1 << 14; - static final int SCAN_AS_FULL_APP = 1 << 15; - static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 16; - static final int SCAN_AS_SYSTEM = 1 << 17; - static final int SCAN_AS_PRIVILEGED = 1 << 18; - static final int SCAN_AS_OEM = 1 << 19; - static final int SCAN_AS_VENDOR = 1 << 20; - static final int SCAN_AS_PRODUCT = 1 << 21; - static final int SCAN_AS_SYSTEM_EXT = 1 << 22; - static final int SCAN_AS_ODM = 1 << 23; + static final int SCAN_DONT_KILL_APP = 1 << 10; + static final int SCAN_IGNORE_FROZEN = 1 << 11; + static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 12; + static final int SCAN_AS_INSTANT_APP = 1 << 13; + static final int SCAN_AS_FULL_APP = 1 << 14; + static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 15; + static final int SCAN_AS_SYSTEM = 1 << 16; + static final int SCAN_AS_PRIVILEGED = 1 << 17; + static final int SCAN_AS_OEM = 1 << 18; + static final int SCAN_AS_VENDOR = 1 << 19; + static final int SCAN_AS_PRODUCT = 1 << 20; + static final int SCAN_AS_SYSTEM_EXT = 1 << 21; + static final int SCAN_AS_ODM = 1 << 22; @IntDef(flag = true, prefix = { "SCAN_" }, value = { SCAN_NO_DEX, @@ -486,7 +495,6 @@ public class PackageManagerService extends IPackageManager.Stub SCAN_REQUIRE_KNOWN, SCAN_MOVE, SCAN_INITIAL, - SCAN_CHECK_ONLY, SCAN_DONT_KILL_APP, SCAN_IGNORE_FROZEN, SCAN_FIRST_BOOT_OR_UPGRADE, @@ -605,11 +613,19 @@ public class PackageManagerService extends IPackageManager.Stub public static final int REASON_LAST = REASON_SHARED; /** - * Whether the package parser cache is enabled. + * The initial enabled state of the cache before other checks are done. */ private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true; /** + * Whether to skip all other checks and force the cache to be enabled. + * + * Setting this to true will cause the cache to be named "debug" to avoid eviction from + * build fingerprint changes. + */ + private static final boolean FORCE_PACKAGE_PARSED_CACHE_ENABLED = false; + + /** * Permissions required in order to receive instant application lifecycle broadcasts. */ private static final String[] INSTANT_APP_BROADCAST_PERMISSION = @@ -666,7 +682,7 @@ public class PackageManagerService extends IPackageManager.Stub // Keys are String (package name), values are Package. @GuardedBy("mLock") - final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<>(); + final ArrayMap<String, AndroidPackage> mPackages = new ArrayMap<>(); // Keys are isolated uids and values are the uid of the application // that created the isolated proccess. @@ -751,7 +767,7 @@ public class PackageManagerService extends IPackageManager.Stub * specificity (the more generic, the earlier in the list a partition appears). */ @VisibleForTesting(visibility = Visibility.PRIVATE) - static final List<SystemPartition> SYSTEM_PARTITIONS = Collections.unmodifiableList( + public static final List<SystemPartition> SYSTEM_PARTITIONS = Collections.unmodifiableList( Arrays.asList( new SystemPartition(Environment.getRootDirectory(), 0 /* scanFlag */, false /* hasOverlays */), @@ -990,12 +1006,12 @@ public class PackageManagerService extends IPackageManager.Stub new ArrayMap<>(); // Mapping from instrumentation class names to info about them. - final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation = + final ArrayMap<ComponentName, ParsedInstrumentation> mInstrumentation = new ArrayMap<>(); // Packages whose data we have transfered into another package, thus // should no longer exist. - final ArraySet<String> mTransferedPackages = new ArraySet<>(); + final ArraySet<String> mTransferredPackages = new ArraySet<>(); // Broadcast actions that are only available to the system. @GuardedBy("mProtectedBroadcasts") @@ -1039,13 +1055,13 @@ public class PackageManagerService extends IPackageManager.Stub final ActivityInfo mResolveActivity = new ActivityInfo(); final ResolveInfo mResolveInfo = new ResolveInfo(); ComponentName mResolveComponentName; - PackageParser.Package mPlatformPackage; + AndroidPackage mPlatformPackage; ComponentName mCustomResolverComponentName; boolean mResolverReplaced = false; private final @Nullable ComponentName mIntentFilterVerifierComponent; - private final @Nullable IntentFilterVerifier<ActivityIntentInfo> mIntentFilterVerifier; + private final @Nullable IntentFilterVerifier<ParsedActivityIntentInfo> mIntentFilterVerifier; private int mIntentFilterVerificationToken = 0; @@ -1080,14 +1096,19 @@ public class PackageManagerService extends IPackageManager.Stub private final IncrementalManager mIncrementalManager; private static class IFVerificationParams { - PackageParser.Package pkg; + String packageName; + boolean hasDomainUrls; + List<ParsedActivity> activities; boolean replacing; int userId; int verifierUid; - public IFVerificationParams(PackageParser.Package _pkg, boolean _replacing, + public IFVerificationParams(String packageName, boolean hasDomainUrls, + List<ParsedActivity> activities, boolean _replacing, int _userId, int _verifierUid) { - pkg = _pkg; + this.packageName = packageName; + this.hasDomainUrls = hasDomainUrls; + this.activities = activities; replacing = _replacing; userId = _userId; verifierUid = _verifierUid; @@ -1101,7 +1122,7 @@ public class PackageManagerService extends IPackageManager.Stub void receiveVerificationResponse(int verificationId); } - private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> { + private class IntentVerifierProxy implements IntentFilterVerifier<ParsedActivityIntentInfo> { private Context mContext; private ComponentName mIntentFilterVerifierComponent; private ArrayList<Integer> mCurrentIntentFilterVerifications = new ArrayList<>(); @@ -1126,11 +1147,11 @@ public class PackageManagerService extends IPackageManager.Stub String packageName = ivs.getPackageName(); - ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters(); + ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters(); final int filterCount = filters.size(); ArraySet<String> domainsSet = new ArraySet<>(); for (int m=0; m<filterCount; m++) { - PackageParser.ActivityIntentInfo filter = filters.get(m); + ParsedActivityIntentInfo filter = filters.get(m); domainsSet.addAll(filter.getHostsList()); } synchronized (mLock) { @@ -1182,14 +1203,14 @@ public class PackageManagerService extends IPackageManager.Stub final boolean verified = ivs.isVerified(); - ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters(); + ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters(); final int count = filters.size(); if (DEBUG_DOMAIN_VERIFICATION) { Slog.i(TAG, "Received verification response " + verificationId + " for " + count + " filters, verified=" + verified); } for (int n=0; n<count; n++) { - PackageParser.ActivityIntentInfo filter = filters.get(n); + ParsedActivityIntentInfo filter = filters.get(n); filter.setVerified(verified); if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "IntentFilter " + filter.toString() @@ -1302,7 +1323,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean addOneIntentFilterVerification(int verifierUid, int userId, int verificationId, - ActivityIntentInfo filter, String packageName) { + ParsedActivityIntentInfo filter, String packageName) { if (!hasValidDomains(filter)) { return false; } @@ -1331,7 +1352,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - private static boolean hasValidDomains(ActivityIntentInfo filter) { + private static boolean hasValidDomains(ParsedActivityIntentInfo filter) { return filter.hasCategory(Intent.CATEGORY_BROWSABLE) && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) || filter.hasDataScheme(IntentFilter.SCHEME_HTTPS)); @@ -1418,6 +1439,7 @@ public class PackageManagerService extends IPackageManager.Stub static final int ENABLE_ROLLBACK_TIMEOUT = 22; static final int DEFERRED_NO_KILL_POST_DELETE = 23; static final int DEFERRED_NO_KILL_INSTALL_OBSERVER = 24; + static final int INTEGRITY_VERIFICATION_COMPLETE = 25; static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000; static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500; @@ -1582,6 +1604,10 @@ public class PackageManagerService extends IPackageManager.Stub final boolean didRestore = (msg.arg2 != 0); mRunningInstalls.delete(msg.arg1); + if (data != null && data.res.freezer != null) { + data.res.freezer.close(); + } + if (data != null && data.mPostInstallRunnable != null) { data.mPostInstallRunnable.run(); } else if (data != null) { @@ -1598,7 +1624,7 @@ public class PackageManagerService extends IPackageManager.Stub final List<String> whitelistedRestrictedPermissions = ((args.installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0 && parentRes.pkg != null) - ? parentRes.pkg.requestedPermissions + ? parentRes.pkg.getRequestedPermissions() : args.whitelistedRestrictedPermissions; // Handle the parent package @@ -1742,10 +1768,14 @@ public class PackageManagerService extends IPackageManager.Stub break; } + case INTEGRITY_VERIFICATION_COMPLETE: { + // TODO: implement this case. + break; + } case START_INTENT_FILTER_VERIFICATIONS: { IFVerificationParams params = (IFVerificationParams) msg.obj; - verifyIntentFiltersIfNeeded(params.userId, params.verifierUid, - params.replacing, params.pkg); + verifyIntentFiltersIfNeeded(params.userId, params.verifierUid, params.replacing, + params.packageName, params.hasDomainUrls, params.activities); break; } case INTENT_FILTER_VERIFIED: { @@ -1895,20 +1925,11 @@ public class PackageManagerService extends IPackageManager.Stub ? res.removedInfo.installerPackageName : null; - // If this is the first time we have child packages for a disabled privileged - // app that had no children, we grant requested runtime permissions to the new - // children if the parent on the system image had them already granted. - if (res.pkg.parentPackage != null) { - final int callingUid = Binder.getCallingUid(); - mPermissionManager.grantRuntimePermissionsGrantedToDisabledPackage( - res.pkg, callingUid); - } - synchronized (mLock) { mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers); } - final String packageName = res.pkg.applicationInfo.packageName; + final String packageName = res.pkg.getAppInfoPackageName(); // Determine the set of users who are adding this package for // the first time vs. those who are seeing an update. @@ -1917,7 +1938,7 @@ public class PackageManagerService extends IPackageManager.Stub int[] updateUserIds = EMPTY_INT_ARRAY; int[] instantUserIds = EMPTY_INT_ARRAY; final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0; - final PackageSetting ps = (PackageSetting) res.pkg.mExtras; + final PackageSetting ps = getPackageSetting(res.pkg.getPackageName()); for (int newUser : res.newUsers) { final boolean isInstantApp = ps.getInstantApp(newUser); if (allNewUsers) { @@ -1951,13 +1972,14 @@ public class PackageManagerService extends IPackageManager.Stub } // Send installed broadcasts if the package is not a static shared lib. - if (res.pkg.staticSharedLibName == null) { - mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath); + if (res.pkg.getStaticSharedLibName() == null) { + mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash( + res.pkg.getBaseCodePath()); // Send added for users that see the package for the first time // sendPackageAddedForNewUsers also deals with system apps int appId = UserHandle.getAppId(res.uid); - boolean isSystem = res.pkg.applicationInfo.isSystemApp(); + boolean isSystem = res.pkg.isSystemApp(); sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload, virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds); @@ -2035,30 +2057,30 @@ public class PackageManagerService extends IPackageManager.Stub final StorageManager storage = mInjector.getStorageManager(); VolumeInfo volume = storage.findVolumeByUuid( - res.pkg.applicationInfo.storageUuid.toString()); + res.pkg.getStorageUuid().toString()); int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(res.pkg)); // If the package was installed externally, log it. if (packageExternalStorageType != StorageEnums.UNKNOWN) { StatsLog.write(StatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED, - packageExternalStorageType, res.pkg.packageName); + packageExternalStorageType, res.pkg.getPackageName()); } } if (DEBUG_INSTALL) { Slog.i(TAG, "upgrading pkg " + res.pkg + " is external"); } - final int[] uidArray = new int[]{res.pkg.applicationInfo.uid}; + final int[] uidArray = new int[]{res.pkg.getUid()}; ArrayList<String> pkgList = new ArrayList<>(1); pkgList.add(packageName); sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null); } } else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib for (int i = 0; i < res.libraryConsumers.size(); i++) { - PackageParser.Package pkg = res.libraryConsumers.get(i); + AndroidPackage pkg = res.libraryConsumers.get(i); // send broadcast that all consumers of the static shared library have changed - sendPackageChangedBroadcast(pkg.packageName, false /* dontKillApp */, - new ArrayList<>(Collections.singletonList(pkg.packageName)), - pkg.applicationInfo.uid, null); + sendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */, + new ArrayList<>(Collections.singletonList(pkg.getPackageName())), + pkg.getUid(), null); } } @@ -2188,7 +2210,7 @@ public class PackageManagerService extends IPackageManager.Stub private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info, IPackageInstallObserver2 observer) { - String packageName = info.pkg.packageName; + String packageName = info.pkg.getPackageName(); mNoKillInstallObservers.put(packageName, Pair.create(info, observer)); Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName); mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS); @@ -2368,7 +2390,7 @@ public class PackageManagerService extends IPackageManager.Stub injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES, packageName -> { synchronized (m.mInstallLock) { - final PackageParser.Package pkg; + final AndroidPackage pkg; final SharedUserSetting sharedUser; synchronized (m.mLock) { PackageSetting ps = m.mSettings.getPackageLPr(packageName); @@ -2387,10 +2409,10 @@ public class PackageManagerService extends IPackageManager.Stub final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser, m.mInjector.getCompatibility()); - if (!newSeInfo.equals(pkg.applicationInfo.seInfo)) { + if (!newSeInfo.equals(pkg.getSeInfo())) { Slog.i(TAG, "Updating seInfo for package " + packageName + " from: " - + pkg.applicationInfo.seInfo + " to: " + newSeInfo); - pkg.applicationInfo.seInfo = newSeInfo; + + pkg.getSeInfo() + " to: " + newSeInfo); + pkg.mutate().setSeInfo(newSeInfo); m.prepareAppDataAfterInstallLIF(pkg); } } @@ -2453,7 +2475,7 @@ public class PackageManagerService extends IPackageManager.Stub } @VisibleForTesting(visibility = Visibility.PRIVATE) - static class SystemPartition { + public static class SystemPartition { public final File folder; public final int scanFlag; public final File appFolder; @@ -2605,7 +2627,7 @@ public class PackageManagerService extends IPackageManager.Stub mProtectedPackages = new ProtectedPackages(mContext); - mApexManager = ApexManager.create(mContext); + mApexManager = ApexManager.getInstance(); mAppsFilter = mInjector.getAppsFilter(); mDirsToScanAsSystem = new ArrayList<>(); @@ -2783,11 +2805,11 @@ public class PackageManagerService extends IPackageManager.Stub final List<String> stubSystemApps = new ArrayList<>(); if (!mOnlyCore) { // do this first before mucking with mPackages for the "expecting better" case - final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator(); + final Iterator<AndroidPackage> pkgIterator = mPackages.values().iterator(); while (pkgIterator.hasNext()) { - final PackageParser.Package pkg = pkgIterator.next(); - if (pkg.isStub) { - stubSystemApps.add(pkg.packageName); + final AndroidPackage pkg = pkgIterator.next(); + if (pkg.isStub()) { + stubSystemApps.add(pkg.getPackageName()); } } @@ -2806,7 +2828,7 @@ public class PackageManagerService extends IPackageManager.Stub /* * If the package is scanned, it's not erased. */ - final PackageParser.Package scannedPkg = mPackages.get(ps.name); + final AndroidPackage scannedPkg = mPackages.get(ps.name); if (scannedPkg != null) { /* * If the system app is both scanned and in the @@ -2883,7 +2905,7 @@ public class PackageManagerService extends IPackageManager.Stub // app completely. Otherwise, revoke their system privileges. for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) { final String packageName = possiblyDeletedUpdatedSystemApps.get(i); - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); final String msg; // remove from the disabled system list; do this first so any future @@ -2909,7 +2931,7 @@ public class PackageManagerService extends IPackageManager.Stub // special privileges removePackageLI(pkg, true); try { - final File codePath = new File(pkg.applicationInfo.getCodePath()); + final File codePath = new File(pkg.getAppInfoCodePath()); scanPackageTracedLI(codePath, 0, scanFlags, 0, null); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse updated, ex-system package: " @@ -3105,7 +3127,7 @@ public class PackageManagerService extends IPackageManager.Stub } int count = 0; for (String pkgName : deferPackages) { - PackageParser.Package pkg = null; + AndroidPackage pkg = null; synchronized (mLock) { PackageSetting ps = mSettings.getPackageLPr(pkgName); if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) { @@ -3205,12 +3227,12 @@ public class PackageManagerService extends IPackageManager.Stub // Initialize InstantAppRegistry's Instant App list for all users. final int[] userIds = UserManagerService.getInstance().getUserIds(); - for (PackageParser.Package pkg : mPackages.values()) { + for (AndroidPackage pkg : mPackages.values()) { if (pkg.isSystem()) { continue; } for (int userId : userIds) { - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps == null || !ps.getInstantApp(userId) || !ps.getInstalled(userId)) { continue; } @@ -3297,7 +3319,7 @@ public class PackageManagerService extends IPackageManager.Stub continue; } // skip if the package isn't installed (?!); this should never happen - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { systemStubPackageNames.remove(i); continue; @@ -3341,43 +3363,46 @@ public class PackageManagerService extends IPackageManager.Stub * APK will be installed and the package will be disabled. To recover from this situation, * the user will need to go into system settings and re-enable the package. */ - private boolean enableCompressedPackage(PackageParser.Package stubPkg) { + private boolean enableCompressedPackage(AndroidPackage stubPkg) { final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY | PackageParser.PARSE_ENFORCE_CODE; synchronized (mInstallLock) { - final PackageParser.Package pkg; + final AndroidPackage pkg; try (PackageFreezer freezer = - freezePackage(stubPkg.packageName, "setEnabledSetting")) { + freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) { pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/); synchronized (mLock) { prepareAppDataAfterInstallLIF(pkg); try { - updateSharedLibrariesLocked(pkg, null, mPackages); + updateSharedLibrariesLocked(pkg, null, + Collections.unmodifiableMap(mPackages)); } catch (PackageManagerException e) { Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e); } - mPermissionManager.updatePermissions(pkg.packageName, pkg); + mPermissionManager.updatePermissions(pkg.getPackageName(), pkg); mSettings.writeLPr(); } } catch (PackageManagerException e) { // Whoops! Something went very wrong; roll back to the stub and disable the package try (PackageFreezer freezer = - freezePackage(stubPkg.packageName, "setEnabledSetting")) { + freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) { synchronized (mLock) { // NOTE: Ensure the system package is enabled; even for a compressed stub. // If we don't, installing the system package fails during scan enableSystemPackageLPw(stubPkg); } - installPackageFromSystemLIF(stubPkg.codePath, + installPackageFromSystemLIF(stubPkg.getCodePath(), null /*allUserHandles*/, null /*origUserHandles*/, null /*origPermissionsState*/, true /*writeSettings*/); } catch (PackageManagerException pme) { // Serious WTF; we have to be able to install the stub - Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.packageName, pme); + Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(), + pme); } finally { // Disable the package; the stub by itself is not runnable synchronized (mLock) { - final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName); + final PackageSetting stubPs = mSettings.mPackages.get( + stubPkg.getPackageName()); if (stubPs != null) { stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android"); @@ -3389,31 +3414,33 @@ public class PackageManagerService extends IPackageManager.Stub } clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); - mDexManager.notifyPackageUpdated(pkg.packageName, - pkg.baseCodePath, pkg.splitCodePaths); + mDexManager.notifyPackageUpdated(pkg.getPackageName(), + pkg.getBaseCodePath(), pkg.getSplitCodePaths()); } return true; } - private PackageParser.Package installStubPackageLI(PackageParser.Package stubPkg, + private AndroidPackage installStubPackageLI(AndroidPackage stubPkg, @ParseFlags int parseFlags, @ScanFlags int scanFlags) throws PackageManagerException { if (DEBUG_COMPRESSION) { - Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.packageName); + Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName()); } // uncompress the binary to its eventual destination on /data - final File scanFile = decompressPackage(stubPkg.packageName, stubPkg.codePath); + final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getCodePath()); if (scanFile == null) { - throw new PackageManagerException("Unable to decompress stub at " + stubPkg.codePath); + throw new PackageManagerException( + "Unable to decompress stub at " + stubPkg.getCodePath()); } synchronized (mLock) { - mSettings.disableSystemPackageLPw(stubPkg.packageName, true /*replaced*/); + mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/); } removePackageLI(stubPkg, true /*chatty*/); try { return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null); } catch (PackageManagerException e) { - Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.packageName, e); + Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(), + e); // Remove the failed install removeCodePathLI(scanFile); throw e; @@ -3496,18 +3523,20 @@ public class PackageManagerService extends IPackageManager.Stub } private static @Nullable File preparePackageParserCache() { - if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) { - return null; - } + if (!FORCE_PACKAGE_PARSED_CACHE_ENABLED) { + if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) { + return null; + } - // Disable package parsing on eng builds to allow for faster incremental development. - if (Build.IS_ENG) { - return null; - } + // Disable package parsing on eng builds to allow for faster incremental development. + if (Build.IS_ENG) { + return null; + } - if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) { - Slog.i(TAG, "Disabling package parser cache due to system property."); - return null; + if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) { + Slog.i(TAG, "Disabling package parser cache due to system property."); + return null; + } } // The base directory for the package parser cache lives under /data/system/. @@ -3519,10 +3548,12 @@ public class PackageManagerService extends IPackageManager.Stub // There are several items that need to be combined together to safely // identify cached items. In particular, changing the value of certain // feature flags should cause us to invalidate any caches. - final String cacheName = SystemProperties.digestOf( - "ro.build.fingerprint", - StorageManager.PROP_ISOLATED_STORAGE, - StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT); + final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug" + : SystemProperties.digestOf( + "ro.build.fingerprint", + StorageManager.PROP_ISOLATED_STORAGE, + StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT + ); // Reconcile cache directories, keeping only what we'd actually use. for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) { @@ -3846,7 +3877,7 @@ public class PackageManagerService extends IPackageManager.Stub ArraySet<String> packages = systemConfig.getLinkedApps(); for (String packageName : packages) { - PackageParser.Package pkg = mPackages.get(packageName); + AndroidPackage pkg = mPackages.get(packageName); if (pkg != null) { if (!pkg.isSystem()) { Slog.w(TAG, "Non-system app '" + packageName + "' in sysconfig <app-link>"); @@ -3854,13 +3885,15 @@ public class PackageManagerService extends IPackageManager.Stub } ArraySet<String> domains = null; - for (PackageParser.Activity a : pkg.activities) { - for (ActivityIntentInfo filter : a.intents) { - if (hasValidDomains(filter)) { - if (domains == null) { - domains = new ArraySet<>(); + if (pkg.getActivities() != null) { + for (ParsedActivity a : pkg.getActivities()) { + for (ParsedActivityIntentInfo filter : a.intents) { + if (hasValidDomains(filter)) { + if (domains == null) { + domains = new ArraySet<>(); + } + domains.addAll(filter.getHostsList()); } - domains.addAll(filter.getHostsList()); } } } @@ -3976,7 +4009,7 @@ public class PackageManagerService extends IPackageManager.Stub } final PackageUserState state = ps.readUserState(userId); - PackageParser.Package p = ps.pkg; + AndroidPackage p = ps.pkg; if (p != null) { final PermissionsState permissionsState = ps.getPermissionsState(); @@ -3984,10 +4017,10 @@ public class PackageManagerService extends IPackageManager.Stub final int[] gids = (flags & PackageManager.GET_GIDS) == 0 ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId); // Compute granted permissions only if package has requested permissions - final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions) + final Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions()) ? Collections.emptySet() : permissionsState.getPermissions(userId); - PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags, + PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags, ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId); if (packageInfo == null) { @@ -4050,7 +4083,7 @@ public class PackageManagerService extends IPackageManager.Stub throw new SecurityException("Package " + packageName + " is currently frozen!"); } - if (!userKeyUnlocked && !ps.pkg.applicationInfo.isEncryptionAware()) { + if (!userKeyUnlocked && !ps.pkg.isEncryptionAware()) { throw new SecurityException("Package " + packageName + " is not encryption aware!"); } } @@ -4063,9 +4096,9 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "is package available"); synchronized (mLock) { - PackageParser.Package p = mPackages.get(packageName); + AndroidPackage p = mPackages.get(packageName); if (p != null) { - final PackageSetting ps = (PackageSetting) p.mExtras; + final PackageSetting ps = getPackageSetting(p.getPackageName()); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return false; } @@ -4130,21 +4163,22 @@ public class PackageManagerService extends IPackageManager.Stub } } - PackageParser.Package p = mPackages.get(packageName); + AndroidPackage p = mPackages.get(packageName); if (matchFactoryOnly && p != null && !isSystemApp(p)) { return null; } if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getPackageInfo " + packageName + ": " + p); if (p != null) { - final PackageSetting ps = (PackageSetting) p.mExtras; + final PackageSetting ps = getPackageSetting(p.getPackageName()); if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) { return null; } if (ps != null && shouldFilterApplicationLocked(ps, filterCallingUid, userId)) { return null; } - return generatePackageInfo((PackageSetting)p.mExtras, flags, userId); + + return generatePackageInfo(ps, flags, userId); } if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) { final PackageSetting ps = mSettings.mPackages.get(packageName); @@ -4180,34 +4214,34 @@ public class PackageManagerService extends IPackageManager.Stub private boolean isComponentVisibleToInstantApp( @Nullable ComponentName component, @ComponentType int type) { if (type == TYPE_ACTIVITY) { - final PackageParser.Activity activity = mComponentResolver.getActivity(component); + final ParsedActivity activity = mComponentResolver.getActivity(component); if (activity == null) { return false; } final boolean visibleToInstantApp = - (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; + (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; final boolean explicitlyVisibleToInstantApp = - (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; + (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; return visibleToInstantApp && explicitlyVisibleToInstantApp; } else if (type == TYPE_RECEIVER) { - final PackageParser.Activity activity = mComponentResolver.getReceiver(component); + final ParsedActivity activity = mComponentResolver.getReceiver(component); if (activity == null) { return false; } final boolean visibleToInstantApp = - (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; + (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; final boolean explicitlyVisibleToInstantApp = - (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; + (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; return visibleToInstantApp && !explicitlyVisibleToInstantApp; } else if (type == TYPE_SERVICE) { - final PackageParser.Service service = mComponentResolver.getService(component); + final ParsedService service = mComponentResolver.getService(component); return service != null - ? (service.info.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 + ? (service.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 : false; } else if (type == TYPE_PROVIDER) { - final PackageParser.Provider provider = mComponentResolver.getProvider(component); + final ParsedProvider provider = mComponentResolver.getProvider(component); return provider != null - ? (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 + ? (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 : false; } else if (type == TYPE_UNKNOWN) { return isComponentVisibleToInstantApp(component); @@ -4251,16 +4285,16 @@ public class PackageManagerService extends IPackageManager.Stub // request for a specific component; if it hasn't been explicitly exposed through // property or instrumentation target, filter if (component != null) { - final PackageParser.Instrumentation instrumentation = + final ParsedInstrumentation instrumentation = mInstrumentation.get(component); if (instrumentation != null - && isCallerSameApp(instrumentation.info.targetPackage, callingUid)) { + && isCallerSameApp(instrumentation.getTargetPackage(), callingUid)) { return false; } return !isComponentVisibleToInstantApp(component, componentType); } // request for application; if no components have been explicitly exposed, filter - return !ps.pkg.visibleToInstantApps; + return !ps.pkg.isVisibleToInstantApps(); } if (ps.getInstantApp(userId)) { // caller can see all components of all instant applications, don't filter @@ -4309,12 +4343,12 @@ public class PackageManagerService extends IPackageManager.Stub } // No package means no static lib as it is always on internal storage - if (ps == null || ps.pkg == null || !ps.pkg.applicationInfo.isStaticSharedLibrary()) { + if (ps == null || ps.pkg == null || !ps.pkg.isStaticSharedLibrary()) { return false; } - final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(ps.pkg.staticSharedLibName, - ps.pkg.staticSharedLibVersion); + final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr( + ps.pkg.getStaticSharedLibName(), ps.pkg.getStaticSharedLibVersion()); if (libraryInfo == null) { return false; } @@ -4336,7 +4370,8 @@ public class PackageManagerService extends IPackageManager.Stub if (index < 0) { continue; } - if (uidPs.pkg.usesStaticLibrariesVersions[index] == libraryInfo.getLongVersion()) { + if (uidPs.pkg.getUsesStaticLibrariesVersions()[index] + == libraryInfo.getLongVersion()) { return false; } } @@ -4410,13 +4445,13 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { - final PackageParser.Package p = mPackages.get(packageName); + final AndroidPackage p = mPackages.get(packageName); if (p != null && p.isMatch(flags)) { - PackageSetting ps = (PackageSetting) p.mExtras; + PackageSetting ps = getPackageSetting(p.getPackageName()); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return -1; } - return UserHandle.getUid(userId, p.applicationInfo.uid); + return UserHandle.getUid(userId, p.getUid()); } if ((flags & MATCH_KNOWN_PACKAGES) != 0) { final PackageSetting ps = mSettings.mPackages.get(packageName); @@ -4440,9 +4475,9 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { - final PackageParser.Package p = mPackages.get(packageName); + final AndroidPackage p = mPackages.get(packageName); if (p != null && p.isMatch(flags)) { - PackageSetting ps = (PackageSetting) p.mExtras; + PackageSetting ps = getPackageSetting(p.getPackageName()); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return null; } @@ -4492,7 +4527,7 @@ public class PackageManagerService extends IPackageManager.Stub } return null; } - ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags, + ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, flags, ps.readUserState(userId), userId); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(ps.pkg); @@ -4530,7 +4565,7 @@ public class PackageManagerService extends IPackageManager.Stub packageName = resolveInternalPackageNameLPr(packageName, PackageManager.VERSION_CODE_HIGHEST); - PackageParser.Package p = mPackages.get(packageName); + AndroidPackage p = mPackages.get(packageName); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getApplicationInfo " + packageName + ": " + p); @@ -4544,7 +4579,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } // Note: isEnabledLP() does not apply here - always return info - ApplicationInfo ai = PackageParser.generateApplicationInfo( + ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo( p, flags, ps.readUserState(userId), userId); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(p); @@ -4916,17 +4951,19 @@ public class PackageManagerService extends IPackageManager.Stub } synchronized (mLock) { - PackageParser.Activity a = mComponentResolver.getActivity(component); + ParsedActivity a = mComponentResolver.getActivity(component); if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a); - if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) { + + AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName()); + if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplicationLocked( ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) { return null; } - return PackageParser.generateActivityInfo( + return PackageInfoUtils.generateActivityInfo(pkg, a, flags, ps.readUserState(userId), userId); } if (mResolveComponentName.equals(component)) { @@ -4963,7 +5000,7 @@ public class PackageManagerService extends IPackageManager.Stub } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - PackageParser.Activity a = mComponentResolver.getActivity(component); + ParsedActivity a = mComponentResolver.getActivity(component); if (a == null) { return false; } @@ -4993,17 +5030,27 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get receiver info"); synchronized (mLock) { - PackageParser.Activity a = mComponentResolver.getReceiver(component); + ParsedActivity a = mComponentResolver.getReceiver(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getReceiverInfo " + component + ": " + a); - if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) { + + if (a == null) { + return null; + } + + AndroidPackage pkg = mPackages.get(a.getPackageName()); + if (pkg == null) { + return null; + } + + if (mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_RECEIVER, userId)) { return null; } - return PackageParser.generateActivityInfo( + return PackageInfoUtils.generateActivityInfo(pkg, a, flags, ps.readUserState(userId), userId); } } @@ -5182,13 +5229,13 @@ public class PackageManagerService extends IPackageManager.Stub } // If the dependent is a static shared lib, use the public package name String dependentPackageName = ps.name; - if (ps.pkg != null && ps.pkg.applicationInfo.isStaticSharedLibrary()) { - dependentPackageName = ps.pkg.manifestPackageName; + if (ps.pkg != null && ps.pkg.isStaticSharedLibrary()) { + dependentPackageName = ps.pkg.getManifestPackageName(); } versionedPackages.add(new VersionedPackage(dependentPackageName, ps.versionCode)); } else if (ps.pkg != null) { - if (ArrayUtils.contains(ps.pkg.usesLibraries, libName) - || ArrayUtils.contains(ps.pkg.usesOptionalLibraries, libName)) { + if (ArrayUtils.contains(ps.pkg.getUsesLibraries(), libName) + || ArrayUtils.contains(ps.pkg.getUsesOptionalLibraries(), libName)) { if (versionedPackages == null) { versionedPackages = new ArrayList<>(); } @@ -5208,17 +5255,22 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get service info"); synchronized (mLock) { - PackageParser.Service s = mComponentResolver.getService(component); + ParsedService s = mComponentResolver.getService(component); if (DEBUG_PACKAGE_INFO) Log.v( - TAG, "getServiceInfo " + component + ": " + s); - if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) { + TAG, "getServiceInfo " + component + ": " + s); + if (s == null) { + return null; + } + + AndroidPackage pkg = mPackages.get(s.getPackageName()); + if (mSettings.isEnabledAndMatchLPr(pkg, s, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_SERVICE, userId)) { return null; } - return PackageParser.generateServiceInfo( + return PackageInfoUtils.generateServiceInfo(pkg, s, flags, ps.readUserState(userId), userId); } } @@ -5233,18 +5285,27 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get provider info"); synchronized (mLock) { - PackageParser.Provider p = mComponentResolver.getProvider(component); + ParsedProvider p = mComponentResolver.getProvider(component); if (DEBUG_PACKAGE_INFO) Log.v( - TAG, "getProviderInfo " + component + ": " + p); - if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) { + TAG, "getProviderInfo " + component + ": " + p); + if (p == null) { + return null; + } + + AndroidPackage pkg = mPackages.get(p.getPackageName()); + if (pkg == null) { + return null; + } + + if (mSettings.isEnabledAndMatchLPr(pkg, p, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_PROVIDER, userId)) { return null; } - return PackageParser.generateProviderInfo( - p, flags, ps.readUserState(userId), userId); + PackageUserState state = ps.readUserState(userId); + return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, userId); } } return null; @@ -5502,21 +5563,21 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int checkSignatures(String pkg1, String pkg2) { synchronized (mLock) { - final PackageParser.Package p1 = mPackages.get(pkg1); - final PackageParser.Package p2 = mPackages.get(pkg2); - if (p1 == null || p1.mExtras == null - || p2 == null || p2.mExtras == null) { + final AndroidPackage p1 = mPackages.get(pkg1); + final AndroidPackage p2 = mPackages.get(pkg2); + final PackageSetting ps1 = p1 == null ? null : getPackageSetting(p1.getPackageName()); + final PackageSetting ps2 = p2 == null ? null : getPackageSetting(p2.getPackageName()); + if (p1 == null || ps1 == null || p2 == null || ps2 == null) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - final PackageSetting ps1 = (PackageSetting) p1.mExtras; - final PackageSetting ps2 = (PackageSetting) p2.mExtras; if (shouldFilterApplicationLocked(ps1, callingUid, callingUserId) || shouldFilterApplicationLocked(ps2, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - return compareSignatures(p1.mSigningDetails.signatures, p2.mSigningDetails.signatures); + return compareSignatures(p1.getSigningDetails().signatures, + p2.getSigningDetails().signatures); } } @@ -5579,21 +5640,21 @@ public class PackageManagerService extends IPackageManager.Stub String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) { synchronized (mLock) { - final PackageParser.Package p = mPackages.get(packageName); - if (p == null || p.mExtras == null) { + final AndroidPackage p = mPackages.get(packageName); + final PackageSetting ps = getPackageSetting(p.getPackageName()); + if (p == null || ps == null) { return false; } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - final PackageSetting ps = (PackageSetting) p.mExtras; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return false; } switch (type) { case CERT_INPUT_RAW_X509: - return p.mSigningDetails.hasCertificate(certificate); + return p.getSigningDetails().hasCertificate(certificate); case CERT_INPUT_SHA256: - return p.mSigningDetails.hasSha256Certificate(certificate); + return p.getSigningDetails().hasSha256Certificate(certificate); default: return false; } @@ -5646,16 +5707,16 @@ public class PackageManagerService extends IPackageManager.Stub * external storage) is less than the version where package signatures * were updated, return true. */ - private boolean isCompatSignatureUpdateNeeded(PackageParser.Package scannedPkg) { - return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(scannedPkg)); + private boolean isCompatSignatureUpdateNeeded(AndroidPackage pkg) { + return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(pkg)); } private static boolean isCompatSignatureUpdateNeeded(VersionInfo ver) { return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY; } - private boolean isRecoverSignatureUpdateNeeded(PackageParser.Package scannedPkg) { - return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(scannedPkg)); + private boolean isRecoverSignatureUpdateNeeded(AndroidPackage pkg) { + return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(pkg)); } private static boolean isRecoverSignatureUpdateNeeded(VersionInfo ver) { @@ -5674,24 +5735,23 @@ public class PackageManagerService extends IPackageManager.Stub final List<String> result = new ArrayList<>(); if (instantAppPkgName != null) { // caller is an instant application; filter unexposed applications - for (PackageParser.Package pkg : mPackages.values()) { - if (!pkg.visibleToInstantApps) { + for (AndroidPackage pkg : mPackages.values()) { + if (!pkg.isVisibleToInstantApps()) { continue; } - result.add(pkg.packageName); + result.add(pkg.getPackageName()); } } else { // caller is a normal application; filter instant applications - for (PackageParser.Package pkg : mPackages.values()) { - final PackageSetting ps = - pkg.mExtras != null ? (PackageSetting) pkg.mExtras : null; + for (AndroidPackage pkg : mPackages.values()) { + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps != null && ps.getInstantApp(callingUserId) && !mInstantAppRegistry.isInstantAccessGranted( callingUserId, UserHandle.getAppId(callingUid), ps.appId)) { continue; } - result.add(pkg.packageName); + result.add(pkg.getPackageName()); } } return result; @@ -6535,7 +6595,7 @@ public class PackageManagerService extends IPackageManager.Stub if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; final boolean isInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid)); - return isInstantApp ? ps.pkg.packageName : null; + return isInstantApp ? ps.pkg.getPackageName() : null; } } return null; @@ -6607,9 +6667,11 @@ public class PackageManagerService extends IPackageManager.Stub list.add(ri); } } - return applyPostResolutionFilter( + + List<ResolveInfo> result = applyPostResolutionFilter( list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent); + return result; } // reader @@ -6686,11 +6748,11 @@ public class PackageManagerService extends IPackageManager.Stub sortResult = true; } } else { - final PackageParser.Package pkg = mPackages.get(pkgName); + final AndroidPackage pkg = mPackages.get(pkgName); result = null; if (pkg != null) { result = filterIfNotSystemUser(mComponentResolver.queryActivities( - intent, resolvedType, flags, pkg.activities, userId), userId); + intent, resolvedType, flags, pkg.getActivities(), userId), userId); } if (result == null || result.size() == 0) { // the caller wants to resolve for a particular package; however, there @@ -7584,10 +7646,10 @@ public class PackageManagerService extends IPackageManager.Stub result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId, intent); } - final PackageParser.Package pkg = mPackages.get(pkgName); + final AndroidPackage pkg = mPackages.get(pkgName); if (pkg != null) { final List<ResolveInfo> result = mComponentResolver.queryReceivers( - intent, resolvedType, flags, pkg.receivers, userId); + intent, resolvedType, flags, pkg.getReceivers(), userId); if (result == null) { return Collections.emptyList(); } @@ -7693,10 +7755,10 @@ public class PackageManagerService extends IPackageManager.Stub resolveInfos, instantAppPkgName); } - final PackageParser.Package pkg = mPackages.get(pkgName); + final AndroidPackage pkg = mPackages.get(pkgName); if (pkg != null) { final List<ResolveInfo> resolveInfos = mComponentResolver.queryServices(intent, - resolvedType, flags, pkg.services, + resolvedType, flags, pkg.getServices(), userId); if (resolveInfos == null) { return Collections.emptyList(); @@ -7820,11 +7882,11 @@ public class PackageManagerService extends IPackageManager.Stub resolveInfos, instantAppPkgName); } - final PackageParser.Package pkg = mPackages.get(pkgName); + final AndroidPackage pkg = mPackages.get(pkgName); if (pkg != null) { final List<ResolveInfo> resolveInfos = mComponentResolver.queryProviders(intent, resolvedType, flags, - pkg.providers, userId); + pkg.getProviders(), userId); if (resolveInfos == null) { return Collections.emptyList(); } @@ -7914,16 +7976,15 @@ public class PackageManagerService extends IPackageManager.Stub } } else { list = new ArrayList<>(mPackages.size()); - for (PackageParser.Package p : mPackages.values()) { - final PackageSetting ps = (PackageSetting) p.mExtras; + for (AndroidPackage p : mPackages.values()) { + final PackageSetting ps = getPackageSetting(p.getPackageName()); if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) { continue; } if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } - final PackageInfo pi = generatePackageInfo((PackageSetting) - p.mExtras, flags, userId); + final PackageInfo pi = generatePackageInfo(ps, flags, userId); if (pi != null) { list.add(pi); } @@ -8002,8 +8063,8 @@ public class PackageManagerService extends IPackageManager.Stub userId); } } else { - for (PackageParser.Package pkg : mPackages.values()) { - PackageSetting ps = (PackageSetting)pkg.mExtras; + for (AndroidPackage pkg : mPackages.values()) { + PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps != null) { addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags, userId); @@ -8056,7 +8117,7 @@ public class PackageManagerService extends IPackageManager.Stub if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } - ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags, + ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, effectiveFlags, ps.readUserState(userId), userId); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(ps.pkg); @@ -8073,16 +8134,16 @@ public class PackageManagerService extends IPackageManager.Stub } } else { list = new ArrayList<>(mPackages.size()); - for (PackageParser.Package p : mPackages.values()) { - if (p.mExtras != null) { - PackageSetting ps = (PackageSetting) p.mExtras; + for (AndroidPackage p : mPackages.values()) { + final PackageSetting ps = getPackageSetting(p.getPackageName()); + if (ps != null) { if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) { continue; } if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } - ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, + ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags, ps.readUserState(userId), userId); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(p); @@ -8138,7 +8199,6 @@ public class PackageManagerService extends IPackageManager.Stub callingUid = mIsolatedOwners.get(callingUid); } final PackageSetting ps = mSettings.mPackages.get(packageName); - PackageParser.Package pkg = mPackages.get(packageName); final boolean returnAllowed = ps != null && (isCallerSameApp(packageName, callingUid) @@ -8209,9 +8269,9 @@ public class PackageManagerService extends IPackageManager.Stub } private boolean isCallerSameApp(String packageName, int uid) { - PackageParser.Package pkg = mPackages.get(packageName); + AndroidPackage pkg = mPackages.get(packageName); return pkg != null - && UserHandle.getAppId(uid) == pkg.applicationInfo.uid; + && UserHandle.getAppId(uid) == pkg.getUid(); } @Override @@ -8227,23 +8287,22 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { - final Iterator<PackageParser.Package> i = mPackages.values().iterator(); + final Iterator<AndroidPackage> i = mPackages.values().iterator(); final int userId = UserHandle.getCallingUserId(); while (i.hasNext()) { - final PackageParser.Package p = i.next(); - if (p.applicationInfo == null) continue; + final AndroidPackage p = i.next(); final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0) - && !p.applicationInfo.isDirectBootAware(); + && !p.isDirectBootAware(); final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0) - && p.applicationInfo.isDirectBootAware(); + && p.isDirectBootAware(); - if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0 + if ((p.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0 && (!mSafeMode || isSystemApp(p)) && (matchesUnaware || matchesAware)) { - PackageSetting ps = mSettings.mPackages.get(p.packageName); + PackageSetting ps = mSettings.mPackages.get(p.getPackageName()); if (ps != null) { - ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, + ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags, ps.readUserState(userId), userId); if (ai != null) { finalList.add(ai); @@ -8341,14 +8400,16 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - final PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); - if (ps == null) return null; + String packageName = component.getPackageName(); + final PackageSetting ps = mSettings.mPackages.get(packageName); + AndroidPackage pkg = mPackages.get(packageName); + if (ps == null || pkg == null) return null; if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) { return null; } - final PackageParser.Instrumentation i = mInstrumentation.get(component); - return PackageParser.generateInstrumentationInfo(i, flags); + final ParsedInstrumentation i = mInstrumentation.get(component); + return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags); } } @@ -8370,15 +8431,18 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { - final Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator(); + final Iterator<ParsedInstrumentation> i = mInstrumentation.values().iterator(); while (i.hasNext()) { - final PackageParser.Instrumentation p = i.next(); + final ParsedInstrumentation p = i.next(); if (targetPackage == null - || targetPackage.equals(p.info.targetPackage)) { - InstrumentationInfo ii = PackageParser.generateInstrumentationInfo(p, - flags); - if (ii != null) { - finalList.add(ii); + || targetPackage.equals(p.getTargetPackage())) { + AndroidPackage pkg = mPackages.get(p.getPackageName()); + if (pkg != null) { + InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p, + pkg, flags); + if (ii != null) { + finalList.add(ii); + } } } } @@ -8432,18 +8496,18 @@ public class PackageManagerService extends IPackageManager.Stub if (throwable == null) { // TODO(toddke): move lower in the scan chain // Static shared libraries have synthetic package names - if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) { - renameStaticSharedLibraryPackage(parseResult.pkg); + if (parseResult.parsedPackage.isStaticSharedLibrary()) { + renameStaticSharedLibraryPackage(parseResult.parsedPackage); } try { - scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags, + addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime, null); } catch (PackageManagerException e) { errorCode = e.error; Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage()); } - } else if (throwable instanceof PackageParser.PackageParserException) { - PackageParser.PackageParserException e = (PackageParser.PackageParserException) + } else if (throwable instanceof PackageParserException) { + PackageParserException e = (PackageParserException) throwable; errorCode = e.error; Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage()); @@ -8467,15 +8531,16 @@ public class PackageManagerService extends IPackageManager.Stub logCriticalInfo(priority, msg); } - private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, + private void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage, boolean forceCollect, boolean skipVerify) throws PackageManagerException { // When upgrading from pre-N MR1, verify the package time stamp using the package // directory and not the APK file. final long lastModifiedTime = mIsPreNMR1Upgrade - ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg); - final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(pkg); + ? new File(parsedPackage.getCodePath()).lastModified() + : getLastModifiedTime(parsedPackage); + final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage); if (ps != null && !forceCollect - && ps.codePathString.equals(pkg.codePath) + && ps.codePathString.equals(parsedPackage.getCodePath()) && ps.timeStamp == lastModifiedTime && !isCompatSignatureUpdateNeeded(settingsVersionForPackage) && !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) { @@ -8485,21 +8550,21 @@ public class PackageManagerService extends IPackageManager.Stub != SignatureSchemeVersion.UNKNOWN) { // Optimization: reuse the existing cached signing data // if the package appears to be unchanged. - pkg.mSigningDetails = - new PackageParser.SigningDetails(ps.signatures.mSigningDetails); + parsedPackage.setSigningDetails( + new PackageParser.SigningDetails(ps.signatures.mSigningDetails)); return; } Slog.w(TAG, "PackageSetting for " + ps.name + " is missing signatures. Collecting certs again to recover them."); } else { - Slog.i(TAG, pkg.codePath + " changed; collecting certs" + + Slog.i(TAG, parsedPackage.getCodePath() + " changed; collecting certs" + (forceCollect ? " (forced)" : "")); } try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); - PackageParser.collectCertificates(pkg, skipVerify); + ApkParseUtils.collectCertificates(parsedPackage, skipVerify); } catch (PackageParserException e) { throw PackageManagerException.from(e); } finally { @@ -8513,20 +8578,20 @@ public class PackageManagerService extends IPackageManager.Stub */ private void maybeClearProfilesForUpgradesLI( @Nullable PackageSetting originalPkgSetting, - @NonNull PackageParser.Package currentPkg) { + @NonNull AndroidPackage pkg) { if (originalPkgSetting == null || !isDeviceUpgrading()) { return; } - if (originalPkgSetting.versionCode == currentPkg.mVersionCode) { + if (originalPkgSetting.versionCode == pkg.getVersionCode()) { return; } - clearAppProfilesLIF(currentPkg, UserHandle.USER_ALL); + clearAppProfilesLIF(pkg, UserHandle.USER_ALL); if (DEBUG_INSTALL) { Slog.d(TAG, originalPkgSetting.name + " clear profile due to version change " + originalPkgSetting.versionCode + " != " - + currentPkg.mVersionCode); + + pkg.getVersionCode()); } } @@ -8535,7 +8600,7 @@ public class PackageManagerService extends IPackageManager.Stub * @see #scanPackageLI(File, int, int, long, UserHandle) */ @GuardedBy({"mInstallLock", "mLock"}) - private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags, + private AndroidPackage scanPackageTracedLI(File scanFile, final int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]"); try { @@ -8550,7 +8615,7 @@ public class PackageManagerService extends IPackageManager.Stub * Returns {@code null} in case of errors and the error code is stored in mLastScanError */ @GuardedBy({"mInstallLock", "mLock"}) - private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags, + private AndroidPackage scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile); PackageParser pp = new PackageParser(); @@ -8560,9 +8625,9 @@ public class PackageManagerService extends IPackageManager.Stub pp.setCallback(mPackageParserCallback); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); - final PackageParser.Package pkg; + final ParsedPackage parsedPackage; try { - pkg = pp.parsePackage(scanFile, parseFlags); + parsedPackage = pp.parseParsedPackage(scanFile, parseFlags, false); } catch (PackageParserException e) { throw PackageManagerException.from(e); } finally { @@ -8570,66 +8635,25 @@ public class PackageManagerService extends IPackageManager.Stub } // Static shared libraries have synthetic package names - if (pkg.applicationInfo.isStaticSharedLibrary()) { - renameStaticSharedLibraryPackage(pkg); - } - - return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user); - } - - /** - * Scans a package and returns the newly parsed package. - * @throws PackageManagerException on a parse error. - */ - @GuardedBy({"mInstallLock", "mLock"}) - private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg, - final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, - @Nullable UserHandle user) - throws PackageManagerException { - // If the package has children and this is the first dive in the function - // we scan the package with the SCAN_CHECK_ONLY flag set to see whether all - // packages (parent and children) would be successfully scanned before the - // actual scan since scanning mutates internal state and we want to atomically - // install the package and its children. - if ((scanFlags & SCAN_CHECK_ONLY) == 0) { - if (pkg.childPackages != null && pkg.childPackages.size() > 0) { - scanFlags |= SCAN_CHECK_ONLY; - } - } else { - scanFlags &= ~SCAN_CHECK_ONLY; - } - - // Scan the parent - PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags, - scanFlags, currentTime, user); - - // Scan the children - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPackage = pkg.childPackages.get(i); - addForInitLI(childPackage, parseFlags, scanFlags, - currentTime, user); - } - - - if ((scanFlags & SCAN_CHECK_ONLY) != 0) { - return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user); + if (parsedPackage.isStaticSharedLibrary()) { + renameStaticSharedLibraryPackage(parsedPackage); } - return scannedPkg; + return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user); } /** * Returns if forced apk verification can be skipped for the whole package, including splits. */ - private boolean canSkipForcedPackageVerification(PackageParser.Package pkg) { - if (!canSkipForcedApkVerification(pkg.baseCodePath)) { + private boolean canSkipForcedPackageVerification(AndroidPackage pkg) { + if (!canSkipForcedApkVerification(pkg.getBaseCodePath())) { return false; } // TODO: Allow base and splits to be verified individually. - if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { - for (int i = 0; i < pkg.splitCodePaths.length; i++) { - if (!canSkipForcedApkVerification(pkg.splitCodePaths[i])) { + String[] splitCodePaths = pkg.getSplitCodePaths(); + if (!ArrayUtils.isEmpty(splitCodePaths)) { + for (int i = 0; i < splitCodePaths.length; i++) { + if (!canSkipForcedApkVerification(splitCodePaths[i])) { return false; } } @@ -8678,7 +8702,7 @@ public class PackageManagerService extends IPackageManager.Stub * <p>NOTE: The return value should be removed. It's the passed in package object. */ @GuardedBy({"mInstallLock", "mLock"}) - private PackageParser.Package addForInitLI(PackageParser.Package pkg, + private AndroidPackage addForInitLI(ParsedPackage parsedPackage, @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { @@ -8694,25 +8718,27 @@ public class PackageManagerService extends IPackageManager.Stub // stack [such as scanPackageOnly()]. However, we verify the application // info prior to that [in scanPackageNew()] and thus have to setup // the application info early. - pkg.setApplicationVolumeUuid(pkg.volumeUuid); - pkg.setApplicationInfoCodePath(pkg.codePath); - pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath); - pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths); - pkg.setApplicationInfoResourcePath(pkg.codePath); - pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath); - pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths); + // TODO(b/135203078): Remove all of these application info calls + parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid()) + .setApplicationInfoCodePath(parsedPackage.getCodePath()) + .setApplicationInfoResourcePath(parsedPackage.getCodePath()) + .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath()) + .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths()); synchronized (mLock) { - renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage); - final String realPkgName = getRealPackageName(pkg, renamedPkgName); + renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage()); + final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName); if (realPkgName != null) { - ensurePackageRenamed(pkg, renamedPkgName); + ensurePackageRenamed(parsedPackage, renamedPkgName); } - final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName); - final PackageSetting installedPkgSetting = mSettings.getPackageLPr(pkg.packageName); + final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage, + renamedPkgName); + final PackageSetting installedPkgSetting = mSettings.getPackageLPr( + parsedPackage.getPackageName()); pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting; pkgAlreadyExists = pkgSetting != null; - final String disabledPkgName = pkgAlreadyExists ? pkgSetting.name : pkg.packageName; + final String disabledPkgName = pkgAlreadyExists + ? pkgSetting.name : parsedPackage.getPackageName(); if (scanSystemPartition && !pkgAlreadyExists && mSettings.getDisabledSystemPkgLPr(disabledPkgName) != null) { // The updated-package data for /system apk remains inconsistently @@ -8730,49 +8756,29 @@ public class PackageManagerService extends IPackageManager.Stub Slog.d(TAG, "updatedPkg = " + disabledPkgSetting); } - final SharedUserSetting sharedUserSetting = (pkg.mSharedUserId != null) - ? mSettings.getSharedUserLPw(pkg.mSharedUserId, + final SharedUserSetting sharedUserSetting = (parsedPackage.getSharedUserId() != null) + ? mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(), 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true) : null; if (DEBUG_PACKAGE_SCANNING && (parseFlags & PackageParser.PARSE_CHATTY) != 0 && sharedUserSetting != null) { - Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId() + " (uid=" + sharedUserSetting.userId + "):" + " packages=" + sharedUserSetting.packages); } if (scanSystemPartition) { - // Potentially prune child packages. If the application on the /system - // partition has been updated via OTA, but, is still disabled by a - // version on /data, cycle through all of its children packages and - // remove children that are no longer defined. if (isSystemPkgUpdated) { - final int scannedChildCount = (pkg.childPackages != null) - ? pkg.childPackages.size() : 0; - final int disabledChildCount = disabledPkgSetting.childPackageNames != null - ? disabledPkgSetting.childPackageNames.size() : 0; - for (int i = 0; i < disabledChildCount; i++) { - String disabledChildPackageName = - disabledPkgSetting.childPackageNames.get(i); - boolean disabledPackageAvailable = false; - for (int j = 0; j < scannedChildCount; j++) { - PackageParser.Package childPkg = pkg.childPackages.get(j); - if (childPkg.packageName.equals(disabledChildPackageName)) { - disabledPackageAvailable = true; - break; - } - } - if (!disabledPackageAvailable) { - mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName); - } - } // we're updating the disabled package, so, scan it as the package setting - final ScanRequest request = new ScanRequest(pkg, sharedUserSetting, null, - disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */, - null /* originalPkgSetting */, null, parseFlags, scanFlags, - (pkg == mPlatformPackage), user); - applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage); + boolean isPlatformPackage = mPlatformPackage != null + && Objects.equals(mPlatformPackage.getPackageName(), + parsedPackage.getPackageName()); + final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting, + null, disabledPkgSetting /* pkgSetting */, + null /* disabledPkgSetting */, null /* originalPkgSetting */, + null, parseFlags, scanFlags, isPlatformPackage, user); + applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage); final ScanResult scanResult = scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L); if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) { @@ -8783,9 +8789,9 @@ public class PackageManagerService extends IPackageManager.Stub } final boolean newPkgChangedPaths = - pkgAlreadyExists && !pkgSetting.codePathString.equals(pkg.codePath); + pkgAlreadyExists && !pkgSetting.codePathString.equals(parsedPackage.getCodePath()); final boolean newPkgVersionGreater = - pkgAlreadyExists && pkg.getLongVersionCode() > pkgSetting.versionCode; + pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode; final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated && newPkgChangedPaths && newPkgVersionGreater; if (isSystemPkgBetter) { @@ -8801,12 +8807,13 @@ public class PackageManagerService extends IPackageManager.Stub logCriticalInfo(Log.WARN, "System package updated;" + " name: " + pkgSetting.name - + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode() - + "; " + pkgSetting.codePathString + " --> " + pkg.codePath); + + "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode() + + "; " + pkgSetting.codePathString + " --> " + parsedPackage.getCodePath()); final InstallArgs args = createInstallArgsForExisting( pkgSetting.codePathString, - pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting)); + pkgSetting.resourcePathString, getAppDexInstructionSets( + pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString)); args.cleanUpResourcesLI(); synchronized (mLock) { mSettings.enableSystemPackageLPw(pkgSetting.name); @@ -8817,9 +8824,10 @@ public class PackageManagerService extends IPackageManager.Stub // The version of the application on the /system partition is less than or // equal to the version on the /data partition. Throw an exception and use // the application already installed on the /data partition. - throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at " - + pkg.codePath + " ignored: updated version " + pkgSetting.versionCode - + " better than this " + pkg.getLongVersionCode()); + throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName() + + " at " + parsedPackage.getCodePath() + " ignored: updated version " + + pkgSetting.versionCode + " better than this " + + parsedPackage.getLongVersionCode()); } // Verify certificates against what was last scanned. Force re-collecting certificate in two @@ -8830,7 +8838,7 @@ public class PackageManagerService extends IPackageManager.Stub final boolean forceCollect = scanSystemPartition ? mIsUpgrade : PackageManagerServiceUtils.isApkVerificationForced(pkgSetting); if (DEBUG_VERIFY && forceCollect) { - Slog.d(TAG, "Force collect certificate of " + pkg.packageName); + Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName()); } // Full APK verification can be skipped during certificate collection, only if the file is @@ -8838,11 +8846,11 @@ public class PackageManagerService extends IPackageManager.Stub // cases, only data in Signing Block is verified instead of the whole file. // TODO(b/136132412): skip for Incremental installation final boolean skipVerify = scanSystemPartition - || (forceCollect && canSkipForcedPackageVerification(pkg)); - collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify); + || (forceCollect && canSkipForcedPackageVerification(parsedPackage)); + collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify); // Reset profile if the application version is changed - maybeClearProfilesForUpgradesLI(pkgSetting, pkg); + maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage); /* * A new system app appeared, but we already had a non-system one of the @@ -8854,17 +8862,20 @@ public class PackageManagerService extends IPackageManager.Stub if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists && !pkgSetting.isSystem()) { - if (!pkg.mSigningDetails.checkCapability(pkgSetting.signatures.mSigningDetails, + if (!parsedPackage.getSigningDetails() + .checkCapability(pkgSetting.signatures.mSigningDetails, PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA) && !pkgSetting.signatures.mSigningDetails.checkCapability( - pkg.mSigningDetails, + parsedPackage.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) { logCriticalInfo(Log.WARN, "System package signature mismatch;" + " name: " + pkgSetting.name); - try (PackageFreezer freezer = freezePackage(pkg.packageName, + try (@SuppressWarnings("unused") PackageFreezer freezer = freezePackage( + parsedPackage.getPackageName(), "scanPackageInternalLI")) { - deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null); + deletePackageLIF(parsedPackage.getPackageName(), null, true, null, 0, null, + false, null); } pkgSetting = null; } else if (newPkgVersionGreater) { @@ -8873,12 +8884,15 @@ public class PackageManagerService extends IPackageManager.Stub // and replace it with the version on /system. logCriticalInfo(Log.WARN, "System package enabled;" - + " name: " + pkgSetting.name - + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode() - + "; " + pkgSetting.codePathString + " --> " + pkg.codePath); + + " name: " + pkgSetting.name + + "; " + pkgSetting.versionCode + " --> " + + parsedPackage.getLongVersionCode() + + "; " + pkgSetting.codePathString + " --> " + + parsedPackage.getCodePath()); InstallArgs args = createInstallArgsForExisting( pkgSetting.codePathString, - pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting)); + pkgSetting.resourcePathString, getAppDexInstructionSets( + pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString)); synchronized (mInstallLock) { args.cleanUpResourcesLI(); } @@ -8889,13 +8903,15 @@ public class PackageManagerService extends IPackageManager.Stub shouldHideSystemApp = true; logCriticalInfo(Log.INFO, "System package disabled;" - + " name: " + pkgSetting.name - + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode - + "; new: " + pkg.codePath + " @ " + pkg.codePath); + + " name: " + pkgSetting.name + + "; old: " + pkgSetting.codePathString + " @ " + + pkgSetting.versionCode + + "; new: " + parsedPackage.getCodePath() + " @ " + + parsedPackage.getCodePath()); } } - final ScanResult scanResult = scanPackageNewLI(pkg, parseFlags, scanFlags + final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user); if (scanResult.success) { synchronized (mLock) { @@ -8908,7 +8924,7 @@ public class PackageManagerService extends IPackageManager.Stub mSharedLibraries, mPackages, Collections.singletonMap( - pkgName, getSettingsVersionForPackage(pkg)), + pkgName, getSettingsVersionForPackage(parsedPackage)), Collections.singletonMap(pkgName, getSharedLibLatestVersionSetting(scanResult))), mSettings.mKeySetManagerService); @@ -8925,16 +8941,17 @@ public class PackageManagerService extends IPackageManager.Stub if (shouldHideSystemApp) { synchronized (mLock) { - mSettings.disableSystemPackageLPw(pkg.packageName, true); + mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true); } } return scanResult.pkgSetting.pkg; } - private static void renameStaticSharedLibraryPackage(PackageParser.Package pkg) { + // TODO:(b/135203078): Move to parsing + private static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) { // Derive the new package synthetic package name - pkg.setPackageName(pkg.packageName + STATIC_SHARED_LIB_DELIMITER - + pkg.staticSharedLibVersion); + parsedPackage.setPackageName(parsedPackage.getPackageName() + STATIC_SHARED_LIB_DELIMITER + + parsedPackage.getStaticSharedLibVersion()); } static String fixProcessName(String defProcessName, String processName) { @@ -9035,7 +9052,7 @@ public class PackageManagerService extends IPackageManager.Stub return; } - List<PackageParser.Package> pkgs; + List<AndroidPackage> pkgs; synchronized (mLock) { pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this); } @@ -9058,8 +9075,8 @@ public class PackageManagerService extends IPackageManager.Stub /* * Return the prebuilt profile path given a package base code path. */ - private static String getPrebuildProfilePath(PackageParser.Package pkg) { - return pkg.baseCodePath + ".prof"; + private static String getPrebuildProfilePath(AndroidPackage pkg) { + return pkg.getBaseCodePath() + ".prof"; } /** @@ -9068,7 +9085,7 @@ public class PackageManagerService extends IPackageManager.Stub * which are (in order) {@code numberOfPackagesOptimized}, {@code numberOfPackagesSkipped} * and {@code numberOfPackagesFailed}. */ - private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog, + private int[] performDexOptUpgrade(List<AndroidPackage> pkgs, boolean showDialog, final int compilationReason, boolean bootComplete) { int numberOfPackagesVisited = 0; @@ -9077,7 +9094,7 @@ public class PackageManagerService extends IPackageManager.Stub int numberOfPackagesFailed = 0; final int numberOfPackagesToDexopt = pkgs.size(); - for (PackageParser.Package pkg : pkgs) { + for (AndroidPackage pkg : pkgs) { numberOfPackagesVisited++; boolean useProfileForDexopt = false; @@ -9093,7 +9110,7 @@ public class PackageManagerService extends IPackageManager.Stub // PackageDexOptimizer to prevent this happening on first boot. The issue // is that we don't have a good way to say "do this only once". if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), - pkg.applicationInfo.uid, pkg.packageName, + pkg.getUid(), pkg.getPackageName(), ArtManager.getProfileName(null))) { Log.e(TAG, "Installer failed to copy system profile!"); } else { @@ -9106,11 +9123,12 @@ public class PackageManagerService extends IPackageManager.Stub e); } } else { - PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName); + PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr( + pkg.getPackageName()); // Handle compressed APKs in this path. Only do this for stubs with profiles to // minimize the number off apps being speed-profile compiled during first boot. // The other paths will not change the filter. - if (disabledPs != null && disabledPs.pkg.isStub) { + if (disabledPs != null && disabledPs.pkg.isStub()) { // The package is the stub one, remove the stub suffix to get the normal // package and APK names. String systemProfilePath = @@ -9129,7 +9147,7 @@ public class PackageManagerService extends IPackageManager.Stub // issue is that we don't have a good way to say "do this only // once". if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), - pkg.applicationInfo.uid, pkg.packageName, + pkg.getUid(), pkg.getPackageName(), ArtManager.getProfileName(null))) { Log.e(TAG, "Failed to copy system profile for stub package!"); } else { @@ -9146,7 +9164,7 @@ public class PackageManagerService extends IPackageManager.Stub if (!PackageDexOptimizer.canOptimizePackage(pkg)) { if (DEBUG_DEXOPT) { - Log.i(TAG, "Skipping update of of non-optimizable app " + pkg.packageName); + Log.i(TAG, "Skipping update of non-optimizable app " + pkg.getPackageName()); } numberOfPackagesSkipped++; continue; @@ -9154,7 +9172,7 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_DEXOPT) { Log.i(TAG, "Updating app " + numberOfPackagesVisited + " of " + - numberOfPackagesToDexopt + ": " + pkg.packageName); + numberOfPackagesToDexopt + ": " + pkg.getPackageName()); } if (showDialog) { @@ -9191,7 +9209,7 @@ public class PackageManagerService extends IPackageManager.Stub dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE; } int primaryDexOptStaus = performDexOptTraced(new DexoptOptions( - pkg.packageName, + pkg.getPackageName(), pkgCompilationReason, dexoptFlags)); @@ -9235,11 +9253,11 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") private void notifyPackageUseLocked(String packageName, int reason) { - final PackageParser.Package p = mPackages.get(packageName); + final AndroidPackage p = mPackages.get(packageName); if (p == null) { return; } - p.mLastPackageUsageTimeInMills[reason] = System.currentTimeMillis(); + p.mutate().setLastPackageUsageTimeInMills(reason, System.currentTimeMillis()); } @Override @@ -9319,7 +9337,7 @@ public class PackageManagerService extends IPackageManager.Stub */ @Override public boolean compileLayouts(String packageName) { - PackageParser.Package pkg; + AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); if (pkg == null) { @@ -9366,7 +9384,7 @@ public class PackageManagerService extends IPackageManager.Stub // Run dexopt on a given package. Returns true if dexopt did not fail, i.e. // if the package can now be considered up to date for the given filter. private int performDexOptInternal(DexoptOptions options) { - PackageParser.Package p; + AndroidPackage p; synchronized (mLock) { p = mPackages.get(options.getPackageName()); if (p == null) { @@ -9389,16 +9407,16 @@ public class PackageManagerService extends IPackageManager.Stub public ArraySet<String> getOptimizablePackages() { ArraySet<String> pkgs = new ArraySet<>(); synchronized (mLock) { - for (PackageParser.Package p : mPackages.values()) { + for (AndroidPackage p : mPackages.values()) { if (PackageDexOptimizer.canOptimizePackage(p)) { - pkgs.add(p.packageName); + pkgs.add(p.getPackageName()); } } } return pkgs; } - private int performDexOptInternalWithDependenciesLI(PackageParser.Package p, + private int performDexOptInternalWithDependenciesLI(AndroidPackage p, DexoptOptions options) { // Select the dex optimizer based on the force parameter. // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to @@ -9415,14 +9433,15 @@ public class PackageManagerService extends IPackageManager.Stub // and the first package that uses the library will dexopt it. The // others will see that the compiled code for the library is up to date. Collection<SharedLibraryInfo> deps = findSharedLibraries(p); - final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo); + final String[] instructionSets = getAppDexInstructionSets(p.getPrimaryCpuAbi(), + p.getSecondaryCpuAbi()); if (!deps.isEmpty()) { DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(), options.getCompilationReason(), options.getCompilerFilter(), options.getSplitName(), options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY); for (SharedLibraryInfo info : deps) { - PackageParser.Package depPackage = null; + AndroidPackage depPackage = null; synchronized (mLock) { depPackage = mPackages.get(info.getPackageName()); } @@ -9430,7 +9449,7 @@ public class PackageManagerService extends IPackageManager.Stub // TODO: Analyze and investigate if we (should) profile libraries. pdo.performDexOpt(depPackage, instructionSets, getOrCreateCompilerPackageStats(depPackage), - mDexManager.getPackageUseInfoOrDefault(depPackage.packageName), + mDexManager.getPackageUseInfoOrDefault(depPackage.getPackageName()), libraryOptions); } else { // TODO(ngeoffray): Support dexopting system shared libraries. @@ -9439,7 +9458,7 @@ public class PackageManagerService extends IPackageManager.Stub } return pdo.performDexOpt(p, instructionSets, getOrCreateCompilerPackageStats(p), - mDexManager.getPackageUseInfoOrDefault(p.packageName), options); + mDexManager.getPackageUseInfoOrDefault(p.getPackageName()), options); } /** @@ -9480,11 +9499,11 @@ public class PackageManagerService extends IPackageManager.Stub } } - private static List<SharedLibraryInfo> findSharedLibraries(PackageParser.Package p) { - if (p.usesLibraryInfos != null) { + private static List<SharedLibraryInfo> findSharedLibraries(AndroidPackage p) { + if (p.getUsesLibraryInfos() != null) { ArrayList<SharedLibraryInfo> retValue = new ArrayList<>(); Set<String> collectedNames = new HashSet<>(); - for (SharedLibraryInfo info : p.usesLibraryInfos) { + for (SharedLibraryInfo info : p.getUsesLibraryInfos()) { findSharedLibrariesRecursive(info, retValue, collectedNames); } return retValue; @@ -9507,13 +9526,13 @@ public class PackageManagerService extends IPackageManager.Stub } } - List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package pkg) { + List<AndroidPackage> findSharedNonSystemLibraries(AndroidPackage pkg) { List<SharedLibraryInfo> deps = findSharedLibraries(pkg); if (!deps.isEmpty()) { - ArrayList<PackageParser.Package> retValue = new ArrayList<>(); + ArrayList<AndroidPackage> retValue = new ArrayList<>(); synchronized (mLock) { for (SharedLibraryInfo info : deps) { - PackageParser.Package depPackage = mPackages.get(info.getPackageName()); + AndroidPackage depPackage = mPackages.get(info.getPackageName()); if (depPackage != null) { retValue.add(depPackage); } @@ -9551,9 +9570,9 @@ public class PackageManagerService extends IPackageManager.Stub return versionedLib.get(version); } - private SharedLibraryInfo getLatestSharedLibraVersionLPr(PackageParser.Package pkg) { + private SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) { LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get( - pkg.staticSharedLibName); + pkg.getStaticSharedLibName()); if (versionedLib == null) { return null; } @@ -9561,7 +9580,7 @@ public class PackageManagerService extends IPackageManager.Stub final int versionCount = versionedLib.size(); for (int i = 0; i < versionCount; i++) { final long libVersion = versionedLib.keyAt(i); - if (libVersion < pkg.staticSharedLibVersion) { + if (libVersion < pkg.getStaticSharedLibVersion()) { previousLibVersion = Math.max(previousLibVersion, libVersion); } } @@ -9577,7 +9596,7 @@ public class PackageManagerService extends IPackageManager.Stub PackageSetting sharedLibPackage = null; synchronized (mLock) { final SharedLibraryInfo latestSharedLibraVersionLPr = - getLatestSharedLibraVersionLPr(scanResult.pkgSetting.pkg); + getLatestSharedLibraVersionLPr(scanResult.request.parsedPackage); if (latestSharedLibraVersionLPr != null) { sharedLibPackage = mSettings.getPackageLPr( latestSharedLibraVersionLPr.getPackageName()); @@ -9606,7 +9625,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void dumpProfiles(String packageName) { - PackageParser.Package pkg; + AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); if (pkg == null) { @@ -9617,7 +9636,7 @@ public class PackageManagerService extends IPackageManager.Stub int callingUid = Binder.getCallingUid(); if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID && - callingUid != pkg.applicationInfo.uid) { + callingUid != pkg.getUid()) { throw new SecurityException("dumpProfiles"); } @@ -9632,7 +9651,7 @@ public class PackageManagerService extends IPackageManager.Stub public void forceDexOpt(String packageName) { enforceSystemOrRoot("forceDexOpt"); - PackageParser.Package pkg; + AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); if (pkg == null) { @@ -9659,15 +9678,15 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) { + private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, AndroidPackage newPkg) { if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { Slog.w(TAG, "Unable to update from " + oldPkg.name - + " to " + newPkg.packageName + + " to " + newPkg.getPackageName() + ": old package not in system partition"); return false; } else if (mPackages.get(oldPkg.name) != null) { Slog.w(TAG, "Unable to update from " + oldPkg.name - + " to " + newPkg.packageName + + " to " + newPkg.getPackageName() + ": old package still exists"); return false; } @@ -9691,122 +9710,86 @@ public class PackageManagerService extends IPackageManager.Stub return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId }; } - private void clearAppDataLIF(PackageParser.Package pkg, int userId, int flags) { + private void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } clearAppDataLeafLIF(pkg, userId, flags); - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - clearAppDataLeafLIF(pkg.childPackages.get(i), userId, flags); - } if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) { clearAppProfilesLIF(pkg, UserHandle.USER_ALL); } } - private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) { + private void clearAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) { final PackageSetting ps; synchronized (mLock) { - ps = mSettings.mPackages.get(pkg.packageName); + ps = mSettings.mPackages.get(pkg.getPackageName()); } for (int realUserId : resolveUserIds(userId)) { final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0; try { - mInstaller.clearAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags, - ceDataInode); + mInstaller.clearAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId, + flags, ceDataInode); } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); } } } - private void destroyAppDataLIF(PackageParser.Package pkg, int userId, int flags) { + private void destroyAppDataLIF(AndroidPackage pkg, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } destroyAppDataLeafLIF(pkg, userId, flags); - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - destroyAppDataLeafLIF(pkg.childPackages.get(i), userId, flags); - } } - private void destroyAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) { + private void destroyAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) { final PackageSetting ps; synchronized (mLock) { - ps = mSettings.mPackages.get(pkg.packageName); + ps = mSettings.mPackages.get(pkg.getPackageName()); } for (int realUserId : resolveUserIds(userId)) { final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0; try { - mInstaller.destroyAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags, - ceDataInode); + mInstaller.destroyAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId, + flags, ceDataInode); } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); } - mDexManager.notifyPackageDataDestroyed(pkg.packageName, userId); + mDexManager.notifyPackageDataDestroyed(pkg.getPackageName(), userId); } } - private void destroyAppProfilesLIF(PackageParser.Package pkg) { + private void destroyAppProfilesLIF(AndroidPackage pkg) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } destroyAppProfilesLeafLIF(pkg); - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - destroyAppProfilesLeafLIF(pkg.childPackages.get(i)); - } } - private void destroyAppProfilesLeafLIF(PackageParser.Package pkg) { + private void destroyAppProfilesLeafLIF(AndroidPackage pkg) { try { - mInstaller.destroyAppProfiles(pkg.packageName); + mInstaller.destroyAppProfiles(pkg.getPackageName()); } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); } } - private void clearAppProfilesLIF(PackageParser.Package pkg, int userId) { + private void clearAppProfilesLIF(AndroidPackage pkg, int userId) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } mArtManagerService.clearAppProfiles(pkg); - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - mArtManagerService.clearAppProfiles(pkg.childPackages.get(i)); - } - } - - private void setInstallAndUpdateTime(PackageParser.Package pkg, long firstInstallTime, - long lastUpdateTime) { - // Set parent install/update time - PackageSetting ps = (PackageSetting) pkg.mExtras; - if (ps != null) { - ps.firstInstallTime = firstInstallTime; - ps.lastUpdateTime = lastUpdateTime; - } - // Set children install/update time - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - ps = (PackageSetting) childPkg.mExtras; - if (ps != null) { - ps.firstInstallTime = firstInstallTime; - ps.lastUpdateTime = lastUpdateTime; - } - } } @GuardedBy("mLock") private void applyDefiningSharedLibraryUpdateLocked( - PackageParser.Package pkg, SharedLibraryInfo libInfo, + AndroidPackage pkg, SharedLibraryInfo libInfo, BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) { // Note that libraries defined by this package may be null if: // - Package manager was unable to create the shared library. The package still @@ -9815,14 +9798,14 @@ public class PackageManagerService extends IPackageManager.Stub // - Package manager is in a state where package isn't scanned yet. This will // get called again after scanning to fix the dependencies. if (pkg.isLibrary()) { - if (pkg.staticSharedLibName != null) { + if (pkg.getStaticSharedLibName() != null) { SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr( - pkg.staticSharedLibName, pkg.staticSharedLibVersion); + pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion()); if (definedLibrary != null) { action.accept(definedLibrary, libInfo); } } else { - for (String libraryName : pkg.libraryNames) { + for (String libraryName : pkg.getLibraryNames()) { SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr( libraryName, SharedLibraryInfo.VERSION_UNDEFINED); if (definedLibrary != null) { @@ -9834,19 +9817,19 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles, - SharedLibraryInfo libInfo, PackageParser.Package changingLib) { + private void addSharedLibraryLPr(AndroidPackage pkg, Set<String> usesLibraryFiles, + SharedLibraryInfo libInfo, AndroidPackage changingLib) { if (libInfo.getPath() != null) { usesLibraryFiles.add(libInfo.getPath()); return; } - PackageParser.Package p = mPackages.get(libInfo.getPackageName()); - if (changingLib != null && changingLib.packageName.equals(libInfo.getPackageName())) { + AndroidPackage p = mPackages.get(libInfo.getPackageName()); + if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) { // If we are doing this while in the middle of updating a library apk, // then we need to make sure to use that new apk for determining the // dependencies here. (We haven't yet finished committing the new apk // to the package manager state.) - if (p == null || p.packageName.equals(changingLib.packageName)) { + if (p == null || p.getPackageName().equals(changingLib.getPackageName())) { p = changingLib; } } @@ -9856,23 +9839,23 @@ public class PackageManagerService extends IPackageManager.Stub applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> { definingLibrary.addDependency(dependency); }); - if (p.usesLibraryFiles != null) { - Collections.addAll(usesLibraryFiles, p.usesLibraryFiles); + if (p.getUsesLibraryFiles() != null) { + Collections.addAll(usesLibraryFiles, p.getUsesLibraryFiles()); } } } @GuardedBy("mLock") - private void updateSharedLibrariesLocked(PackageParser.Package pkg, - PackageParser.Package changingLib, Map<String, PackageParser.Package> availablePackages) + private void updateSharedLibrariesLocked(AndroidPackage pkg, + AndroidPackage changingLib, Map<String, AndroidPackage> availablePackages) throws PackageManagerException { final ArrayList<SharedLibraryInfo> sharedLibraryInfos = collectSharedLibraryInfos(pkg, availablePackages, mSharedLibraries, null); executeSharedLibrariesUpdateLPr(pkg, changingLib, sharedLibraryInfos); } - private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(PackageParser.Package pkg, - Map<String, PackageParser.Package> availablePackages, + private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(AndroidPackage pkg, + Map<String, AndroidPackage> availablePackages, @NonNull final Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries, @Nullable final Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries) throws PackageManagerException { @@ -9883,44 +9866,45 @@ public class PackageManagerService extends IPackageManager.Stub // that libraries are searched in the correct order) and must have no // duplicates. ArrayList<SharedLibraryInfo> usesLibraryInfos = null; - if (pkg.usesLibraries != null) { - usesLibraryInfos = collectSharedLibraryInfos(pkg.usesLibraries, null, null, - pkg.packageName, true, pkg.applicationInfo.targetSdkVersion, null, + if (pkg.getUsesLibraries() != null) { + usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null, + pkg.getPackageName(), true, pkg.getTargetSdkVersion(), null, availablePackages, existingLibraries, newLibraries); } - if (pkg.usesStaticLibraries != null) { - usesLibraryInfos = collectSharedLibraryInfos(pkg.usesStaticLibraries, - pkg.usesStaticLibrariesVersions, pkg.usesStaticLibrariesCertDigests, - pkg.packageName, true, pkg.applicationInfo.targetSdkVersion, usesLibraryInfos, + if (pkg.getUsesStaticLibraries() != null) { + usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(), + pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(), + pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); } - if (pkg.usesOptionalLibraries != null) { - usesLibraryInfos = collectSharedLibraryInfos(pkg.usesOptionalLibraries, - null, null, pkg.packageName, false, pkg.applicationInfo.targetSdkVersion, + if (pkg.getUsesOptionalLibraries() != null) { + usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(), + null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); } return usesLibraryInfos; } - private void executeSharedLibrariesUpdateLPr(PackageParser.Package pkg, - PackageParser.Package changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) { + private void executeSharedLibrariesUpdateLPr(AndroidPackage pkg, + AndroidPackage changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) { // If the package provides libraries, clear their old dependencies. // This method will set them up again. applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> { definingLibrary.clearDependencies(); }); if (usesLibraryInfos != null) { - pkg.usesLibraryInfos = usesLibraryInfos; + pkg.mutate().setUsesLibraryInfos(usesLibraryInfos); // Use LinkedHashSet to preserve the order of files added to // usesLibraryFiles while eliminating duplicates. Set<String> usesLibraryFiles = new LinkedHashSet<>(); for (SharedLibraryInfo libInfo : usesLibraryInfos) { addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib); } - pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[usesLibraryFiles.size()]); + pkg.mutate().setUsesLibraryFiles(usesLibraryFiles.toArray( + new String[usesLibraryFiles.size()])); } else { - pkg.usesLibraryInfos = null; - pkg.usesLibraryFiles = null; + pkg.mutate().setUsesLibraryInfos(null) + .setUsesLibraryFiles(null); } } @@ -9930,7 +9914,7 @@ public class PackageManagerService extends IPackageManager.Stub @Nullable long[] requiredVersions, @Nullable String[][] requiredCertDigests, @NonNull String packageName, boolean required, int targetSdk, @Nullable ArrayList<SharedLibraryInfo> outUsedLibraries, - @NonNull final Map<String, PackageParser.Package> availablePackages, + @NonNull final Map<String, AndroidPackage> availablePackages, @NonNull final Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries, @Nullable final Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries) throws PackageManagerException { @@ -9959,8 +9943,8 @@ public class PackageManagerService extends IPackageManager.Stub + " library " + libName + " version " + libraryInfo.getLongVersion() + "; failing!"); } - PackageParser.Package libPkg = - availablePackages.get(libraryInfo.getPackageName()); + AndroidPackage pkg = availablePackages.get(libraryInfo.getPackageName()); + SigningDetails libPkg = pkg == null ? null : pkg.getSigningDetails(); if (libPkg == null) { throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY, "Package " + packageName + " requires unavailable static shared" @@ -9971,9 +9955,9 @@ public class PackageManagerService extends IPackageManager.Stub // For apps targeting O MR1 we require explicit enumeration of all certs. final String[] libCertDigests = (targetSdk >= Build.VERSION_CODES.O_MR1) ? PackageUtils.computeSignaturesSha256Digests( - libPkg.mSigningDetails.signatures) + libPkg.signatures) : PackageUtils.computeSignaturesSha256Digests( - new Signature[]{libPkg.mSigningDetails.signatures[0]}); + new Signature[]{libPkg.signatures[0]}); // Take a shortcut if sizes don't match. Note that if an app doesn't // target O we don't parse the "additional-certificate" tags similarly @@ -10003,7 +9987,7 @@ public class PackageManagerService extends IPackageManager.Stub // if the new one has been blessed by the old byte[] digestBytes = HexEncoding.decode( expectedCertDigests[0], false /* allowSingleChar */); - if (!libPkg.mSigningDetails.hasSha256Certificate(digestBytes)) { + if (!libPkg.hasSha256Certificate(digestBytes)) { throw new PackageManagerException( INSTALL_FAILED_MISSING_SHARED_LIBRARY, "Package " + packageName + " requires differently signed" + @@ -10035,28 +10019,28 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private ArrayList<PackageParser.Package> updateAllSharedLibrariesLocked( - PackageParser.Package updatedPkg, - Map<String, PackageParser.Package> availablePackages) { - ArrayList<PackageParser.Package> resultList = null; + private ArrayList<AndroidPackage> updateAllSharedLibrariesLocked( + AndroidPackage updatedPkg, + Map<String, AndroidPackage> availablePackages) { + ArrayList<AndroidPackage> resultList = null; // Set of all descendants of a library; used to eliminate cycles ArraySet<String> descendants = null; // The current list of packages that need updating - ArrayList<PackageParser.Package> needsUpdating = null; + ArrayList<AndroidPackage> needsUpdating = null; if (updatedPkg != null) { needsUpdating = new ArrayList<>(1); needsUpdating.add(updatedPkg); } do { - final PackageParser.Package changingPkg = + final AndroidPackage changingPkg = (needsUpdating == null) ? null : needsUpdating.remove(0); for (int i = mPackages.size() - 1; i >= 0; --i) { - final PackageParser.Package pkg = mPackages.valueAt(i); + final AndroidPackage pkg = mPackages.valueAt(i); if (changingPkg != null - && !hasString(pkg.usesLibraries, changingPkg.libraryNames) - && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames) - && !ArrayUtils.contains(pkg.usesStaticLibraries, - changingPkg.staticSharedLibName)) { + && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames()) + && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames()) + && !ArrayUtils.contains(pkg.getUsesStaticLibraries(), + changingPkg.getStaticSharedLibName())) { continue; } if (resultList == null) { @@ -10068,8 +10052,8 @@ public class PackageManagerService extends IPackageManager.Stub if (descendants == null) { descendants = new ArraySet<>(); } - if (!descendants.contains(pkg.packageName)) { - descendants.add(pkg.packageName); + if (!descendants.contains(pkg.getPackageName())) { + descendants.add(pkg.getPackageName()); needsUpdating.add(pkg); } } @@ -10084,8 +10068,9 @@ public class PackageManagerService extends IPackageManager.Stub if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) { final int flags = pkg.isUpdatedSystemApp() ? PackageManager.DELETE_KEEP_DATA : 0; - deletePackageLIF(pkg.packageName, null, true, mUserManager.getUserIds(), - flags , null, true, null); + deletePackageLIF(pkg.getPackageName(), null, true, + mUserManager.getUserIds(), flags, null, + true, null); } Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); } @@ -10095,43 +10080,15 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy({"mInstallLock", "mLock"}) - private List<ScanResult> scanPackageTracedLI(PackageParser.Package pkg, + private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage"); - // If the package has children and this is the first dive in the function - // we recursively scan the package with the SCAN_CHECK_ONLY flag set to see - // whether all packages (parent and children) would be successfully scanned - // before the actual scan since scanning mutates internal state and we want - // to atomically install the package and its children. - if ((scanFlags & SCAN_CHECK_ONLY) == 0) { - if (pkg.childPackages != null && pkg.childPackages.size() > 0) { - scanFlags |= SCAN_CHECK_ONLY; - } - } else { - scanFlags &= ~SCAN_CHECK_ONLY; - } - - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - final List<ScanResult> scanResults = new ArrayList<>(1 + childCount); try { - // Scan the parent - scanResults.add(scanPackageNewLI(pkg, parseFlags, scanFlags, currentTime, user)); - // Scan the children - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - scanResults.add(scanPackageNewLI(childPkg, parseFlags, - scanFlags, currentTime, user)); - } + return scanPackageNewLI(parsedPackage, parseFlags, scanFlags, currentTime, user); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } - - if ((scanFlags & SCAN_CHECK_ONLY) != 0) { - return scanPackageTracedLI(pkg, parseFlags, scanFlags, currentTime, user); - } - - return scanResults; } /** The result of a package scan. */ @@ -10178,9 +10135,9 @@ public class PackageManagerService extends IPackageManager.Stub @VisibleForTesting static class ScanRequest { /** The parsed package */ - @NonNull public final PackageParser.Package pkg; + @NonNull public final ParsedPackage parsedPackage; /** The package this package replaces */ - @Nullable public final PackageParser.Package oldPkg; + @Nullable public final AndroidPackage oldPkg; /** Shared user settings, if the package has a shared user */ @Nullable public final SharedUserSetting sharedUserSetting; /** @@ -10204,9 +10161,9 @@ public class PackageManagerService extends IPackageManager.Stub /** Whether or not the platform package is being scanned */ public final boolean isPlatformPackage; public ScanRequest( - @NonNull PackageParser.Package pkg, + @NonNull ParsedPackage parsedPackage, @Nullable SharedUserSetting sharedUserSetting, - @Nullable PackageParser.Package oldPkg, + @Nullable AndroidPackage oldPkg, @Nullable PackageSetting pkgSetting, @Nullable PackageSetting disabledPkgSetting, @Nullable PackageSetting originalPkgSetting, @@ -10215,7 +10172,7 @@ public class PackageManagerService extends IPackageManager.Stub @ScanFlags int scanFlags, boolean isPlatformPackage, @Nullable UserHandle user) { - this.pkg = pkg; + this.parsedPackage = parsedPackage; this.oldPkg = oldPkg; this.pkgSetting = pkgSetting; this.sharedUserSetting = sharedUserSetting; @@ -10248,7 +10205,7 @@ public class PackageManagerService extends IPackageManager.Stub */ private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags, PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user, - PackageParser.Package pkg) { + AndroidPackage pkg) { // TODO(patb): Do away entirely with disabledPkgSetting here. PkgSetting will always contain // the correct isSystem value now that we don't disable system packages before scan. @@ -10300,12 +10257,14 @@ public class PackageManagerService extends IPackageManager.Stub && SystemProperties.getInt("ro.vndk.version", 28) < 28; if (((scanFlags & SCAN_AS_PRIVILEGED) == 0) && !pkg.isPrivileged() - && (pkg.mSharedUserId != null) + && (pkg.getSharedUserId() != null) && !skipVendorPrivilegeScan) { SharedUserSetting sharedUserSetting = null; try { - sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false); - } catch (PackageManagerException ignore) {} + sharedUserSetting = mSettings.getSharedUserLPw(pkg.getSharedUserId(), 0, + 0, false); + } catch (PackageManagerException ignore) { + } if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { // Exempt SharedUsers signed with the platform key. // TODO(b/72378145) Fix this exemption. Force signature apps @@ -10314,7 +10273,8 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { PackageSetting platformPkgSetting = mSettings.mPackages.get("android"); if ((compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures, - pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) { + pkg.getSigningDetails().signatures) + != PackageManager.SIGNATURE_MATCH)) { scanFlags |= SCAN_AS_PRIVILEGED; } } @@ -10329,46 +10289,50 @@ public class PackageManagerService extends IPackageManager.Stub // method. Also, we need to solve the problem of potentially creating a new shared user // setting. That can probably be done later and patch things up after the fact. @GuardedBy({"mInstallLock", "mLock"}) - private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg, + private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { - final String renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage); - final String realPkgName = getRealPackageName(pkg, renamedPkgName); + final String renamedPkgName = mSettings.getRenamedPackageLPr( + parsedPackage.getRealPackage()); + final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName); if (realPkgName != null) { - ensurePackageRenamed(pkg, renamedPkgName); + ensurePackageRenamed(parsedPackage, renamedPkgName); } - final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName); - final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.packageName); + final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage, + renamedPkgName); + final PackageSetting pkgSetting = mSettings.getPackageLPr(parsedPackage.getPackageName()); final PackageSetting disabledPkgSetting = - mSettings.getDisabledSystemPkgLPr(pkg.packageName); + mSettings.getDisabledSystemPkgLPr(parsedPackage.getPackageName()); - if (mTransferedPackages.contains(pkg.packageName)) { - Slog.w(TAG, "Package " + pkg.packageName + if (mTransferredPackages.contains(parsedPackage.getPackageName())) { + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " was transferred to another, but its .apk remains"); } - scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg); + scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, parsedPackage); synchronized (mLock) { - applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage); - assertPackageIsValid(pkg, parseFlags, scanFlags); + applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage); + assertPackageIsValid(parsedPackage, parseFlags, scanFlags); SharedUserSetting sharedUserSetting = null; - if (pkg.mSharedUserId != null) { + if (parsedPackage.getSharedUserId() != null) { // SIDE EFFECTS; may potentially allocate a new shared user - sharedUserSetting = mSettings.getSharedUserLPw( - pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/); + sharedUserSetting = mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(), + 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/); if (DEBUG_PACKAGE_SCANNING) { if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) - Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId() + " (uid=" + sharedUserSetting.userId + "):" + " packages=" + sharedUserSetting.packages); } } - final ScanRequest request = new ScanRequest(pkg, sharedUserSetting, + String platformPackageName = mPlatformPackage == null + ? null : mPlatformPackage.getPackageName(); + final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting, pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting, originalPkgSetting, realPkgName, parseFlags, scanFlags, - (pkg == mPlatformPackage), user); + Objects.equals(parsedPackage.getPackageName(), platformPackageName), user); return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime); } } @@ -10411,11 +10375,18 @@ public class PackageManagerService extends IPackageManager.Stub * possible and the system is not left in an inconsistent state. */ @GuardedBy({"mLock", "mInstallLock"}) - private void commitReconciledScanResultLocked(@NonNull ReconciledPackage reconciledPkg) { + private AndroidPackage commitReconciledScanResultLocked( + @NonNull ReconciledPackage reconciledPkg) { final ScanResult result = reconciledPkg.scanResult; final ScanRequest request = result.request; - final PackageParser.Package pkg = request.pkg; - final PackageParser.Package oldPkg = request.oldPkg; + // TODO(b/135203078): Move this even further away + ParsedPackage parsedPackage = request.parsedPackage; + if ("android".equals(parsedPackage.getPackageName())) { + // TODO(b/135203078): Move this to initial parse + parsedPackage.setVersionCode(mSdkVersion) + .setVersionCodeMajor(0); + } + final AndroidPackage oldPkg = request.oldPkg; final @ParseFlags int parseFlags = request.parseFlags; final @ScanFlags int scanFlags = request.scanFlags; final PackageSetting oldPkgSetting = request.oldPkgSetting; @@ -10432,14 +10403,12 @@ public class PackageManagerService extends IPackageManager.Stub if (result.existingSettingCopied) { pkgSetting = request.pkgSetting; pkgSetting.updateFrom(result.pkgSetting); - pkg.mExtras = pkgSetting; } else { pkgSetting = result.pkgSetting; if (originalPkgSetting != null) { - mSettings.addRenamedPackageLPw(pkg.packageName, originalPkgSetting.name); - } - if (originalPkgSetting != null && (scanFlags & SCAN_CHECK_ONLY) == 0) { - mTransferedPackages.add(originalPkgSetting.name); + mSettings.addRenamedPackageLPw(parsedPackage.getPackageName(), + originalPkgSetting.name); + mTransferredPackages.add(originalPkgSetting.name); } } if (pkgSetting.sharedUser != null) { @@ -10451,12 +10420,13 @@ public class PackageManagerService extends IPackageManager.Stub // We need to have this here because addUserToSettingLPw() is sometimes responsible // for creating the application ID. If we did this earlier, we would be saving the // correct ID. - pkg.applicationInfo.uid = pkgSetting.appId; + parsedPackage.setUid(pkgSetting.appId); + final AndroidPackage pkg = parsedPackage.hideAsFinal(); mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting); - if ((scanFlags & SCAN_CHECK_ONLY) == 0 && realPkgName != null) { - mTransferedPackages.add(pkg.packageName); + if (realPkgName != null) { + mTransferredPackages.add(pkg.getPackageName()); } if (reconciledPkg.collectedSharedLibraryInfos != null) { @@ -10465,7 +10435,7 @@ public class PackageManagerService extends IPackageManager.Stub final KeySetManagerService ksms = mSettings.mKeySetManagerService; if (reconciledPkg.removeAppKeySetData) { - ksms.removeAppKeySetDataLPw(pkg.packageName); + ksms.removeAppKeySetDataLPw(pkg.getPackageName()); } if (reconciledPkg.sharedUserSignaturesChanged) { pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE; @@ -10473,17 +10443,17 @@ public class PackageManagerService extends IPackageManager.Stub } pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails; - if ((scanFlags & SCAN_CHECK_ONLY) == 0 && pkg.mAdoptPermissions != null) { + if (pkg.getAdoptPermissions() != null) { // This package wants to adopt ownership of permissions from // another package. - for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) { - final String origName = pkg.mAdoptPermissions.get(i); + for (int i = pkg.getAdoptPermissions().size() - 1; i >= 0; i--) { + final String origName = pkg.getAdoptPermissions().get(i); final PackageSetting orig = mSettings.getPackageLPr(origName); if (orig != null) { if (verifyPackageUpdateLPr(orig, pkg)) { Slog.i(TAG, "Adopting permissions from " + origName + " to " - + pkg.packageName); - mSettings.mPermissions.transferPermissions(origName, pkg.packageName); + + pkg.getPackageName()); + mSettings.mPermissions.transferPermissions(origName, pkg.getPackageName()); } } } @@ -10500,21 +10470,15 @@ public class PackageManagerService extends IPackageManager.Stub } } - if ((scanFlags & SCAN_CHECK_ONLY) != 0) { - if (oldPkgSetting != null) { - synchronized (mLock) { - mSettings.mPackages.put(oldPkgSetting.name, oldPkgSetting); - } - } - } else { - final int userId = user == null ? 0 : user.getIdentifier(); - // Modify state for the given package setting - commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags, - (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg); - if (pkgSetting.getInstantApp(userId)) { - mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId); - } + final int userId = user == null ? 0 : user.getIdentifier(); + // Modify state for the given package setting + commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags, + (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg); + if (pkgSetting.getInstantApp(userId)) { + mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId); } + + return pkg; } /** @@ -10522,18 +10486,19 @@ public class PackageManagerService extends IPackageManager.Stub * <p>This may differ from the package's actual name if the application has already * been installed under one of this package's original names. */ - private static @Nullable String getRealPackageName(@NonNull PackageParser.Package pkg, + private static @Nullable String getRealPackageName(@NonNull AndroidPackage pkg, @Nullable String renamedPkgName) { if (isPackageRenamed(pkg, renamedPkgName)) { - return pkg.mRealPackage; + return pkg.getRealPackage(); } return null; } /** Returns {@code true} if the package has been renamed. Otherwise, {@code false}. */ - private static boolean isPackageRenamed(@NonNull PackageParser.Package pkg, + private static boolean isPackageRenamed(@NonNull AndroidPackage pkg, @Nullable String renamedPkgName) { - return pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(renamedPkgName); + return pkg.getOriginalPackages() != null + && pkg.getOriginalPackages().contains(renamedPkgName); } /** @@ -10544,14 +10509,14 @@ public class PackageManagerService extends IPackageManager.Stub * shared user [if any]. */ @GuardedBy("mLock") - private @Nullable PackageSetting getOriginalPackageLocked(@NonNull PackageParser.Package pkg, + private @Nullable PackageSetting getOriginalPackageLocked(@NonNull AndroidPackage pkg, @Nullable String renamedPkgName) { if (!isPackageRenamed(pkg, renamedPkgName)) { return null; } - for (int i = pkg.mOriginalPackages.size() - 1; i >= 0; --i) { + for (int i = ArrayUtils.size(pkg.getOriginalPackages()) - 1; i >= 0; --i) { final PackageSetting originalPs = - mSettings.getPackageLPr(pkg.mOriginalPackages.get(i)); + mSettings.getPackageLPr(pkg.getOriginalPackages().get(i)); if (originalPs != null) { // the package is already installed under its original name... // but, should we use it? @@ -10559,18 +10524,18 @@ public class PackageManagerService extends IPackageManager.Stub // the new package is incompatible with the original continue; } else if (originalPs.sharedUser != null) { - if (!originalPs.sharedUser.name.equals(pkg.mSharedUserId)) { + if (!originalPs.sharedUser.name.equals(pkg.getSharedUserId())) { // the shared user id is incompatible with the original Slog.w(TAG, "Unable to migrate data from " + originalPs.name - + " to " + pkg.packageName + ": old uid " + + " to " + pkg.getPackageName() + ": old uid " + originalPs.sharedUser.name - + " differs from " + pkg.mSharedUserId); + + " differs from " + pkg.getSharedUserId()); continue; } // TODO: Add case when shared user id is added [b/28144775] } else { if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package " - + pkg.packageName + " to old name " + originalPs.name); + + pkg.getPackageName() + " to old name " + originalPs.name); } return originalPs; } @@ -10583,19 +10548,19 @@ public class PackageManagerService extends IPackageManager.Stub * <p>When we've already installed the package under an original name, update * the new package so we can continue to have the old name. */ - private static void ensurePackageRenamed(@NonNull PackageParser.Package pkg, + private static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage, @NonNull String renamedPackageName) { - if (pkg.mOriginalPackages == null - || !pkg.mOriginalPackages.contains(renamedPackageName) - || pkg.packageName.equals(renamedPackageName)) { + if (parsedPackage.getOriginalPackages() == null + || !parsedPackage.getOriginalPackages().contains(renamedPackageName) + || parsedPackage.getPackageName().equals(renamedPackageName)) { return; } - pkg.setPackageName(renamedPackageName); + parsedPackage.setPackageName(renamedPackageName); } /** * Applies the adjusted ABI calculated by - * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, PackageParser.Package)} to all + * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, AndroidPackage)} to all * relevant packages and settings. * @param sharedUserSetting The {@code SharedUserSetting} to adjust * @param scannedPackage the package being scanned or null @@ -10603,22 +10568,20 @@ public class PackageManagerService extends IPackageManager.Stub * @return the list of code paths that belong to packages that had their ABIs adjusted. */ private static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting, - PackageParser.Package scannedPackage, String adjustedAbi) { + ParsedPackage scannedPackage, String adjustedAbi) { if (scannedPackage != null) { - scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi; + scannedPackage.setPrimaryCpuAbi(adjustedAbi); } List<String> changedAbiCodePath = null; for (PackageSetting ps : sharedUserSetting.packages) { - if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) { + if (scannedPackage == null || !scannedPackage.getPackageName().equals(ps.name)) { if (ps.primaryCpuAbiString != null) { continue; } ps.primaryCpuAbiString = adjustedAbi; - if (ps.pkg != null && ps.pkg.applicationInfo != null - && !TextUtils.equals( - adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) { - ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi; + if (ps.pkg != null && !TextUtils.equals(adjustedAbi, ps.pkg.getPrimaryCpuAbi())) { + ps.pkg.mutate().setPrimaryCpuAbi(adjustedAbi); if (DEBUG_ABI_SELECTION) { Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi @@ -10640,42 +10603,42 @@ public class PackageManagerService extends IPackageManager.Stub * Sets the enabled state of components configured through {@link SystemConfig}. * This modifies the {@link PackageSetting} object. **/ - static void configurePackageComponents(PackageParser.Package pkg) { + static void configurePackageComponents(AndroidPackage pkg) { final ArrayMap<String, Boolean> componentsEnabledStates = SystemConfig.getInstance() - .getComponentsEnabledStates(pkg.packageName); + .getComponentsEnabledStates(pkg.getPackageName()); if (componentsEnabledStates == null) { return; } - for (int i = pkg.activities.size() - 1; i >= 0; i--) { - final PackageParser.Activity component = pkg.activities.get(i); + for (int i = ArrayUtils.size(pkg.getActivities()) - 1; i >= 0; i--) { + final ParsedActivity component = pkg.getActivities().get(i); final Boolean enabled = componentsEnabledStates.get(component.className); if (enabled != null) { - component.info.enabled = enabled; + component.setEnabled(enabled); } } - for (int i = pkg.receivers.size() - 1; i >= 0; i--) { - final PackageParser.Activity component = pkg.receivers.get(i); + for (int i = ArrayUtils.size(pkg.getReceivers()) - 1; i >= 0; i--) { + final ParsedActivity component = pkg.getReceivers().get(i); final Boolean enabled = componentsEnabledStates.get(component.className); if (enabled != null) { - component.info.enabled = enabled; + component.setEnabled(enabled); } } - for (int i = pkg.providers.size() - 1; i >= 0; i--) { - final PackageParser.Provider component = pkg.providers.get(i); + for (int i = ArrayUtils.size(pkg.getProviders()) - 1; i >= 0; i--) { + final ParsedProvider component = pkg.getProviders().get(i); final Boolean enabled = componentsEnabledStates.get(component.className); if (enabled != null) { - component.info.enabled = enabled; + component.setEnabled(enabled); } } - for (int i = pkg.services.size() - 1; i >= 0; i--) { - final PackageParser.Service component = pkg.services.get(i); + for (int i = ArrayUtils.size(pkg.getServices()) - 1; i >= 0; i--) { + final ParsedService component = pkg.getServices().get(i); final Boolean enabled = componentsEnabledStates.get(component.className); if (enabled != null) { - component.info.enabled = enabled; + component.setEnabled(enabled); } } } @@ -10702,7 +10665,7 @@ public class PackageManagerService extends IPackageManager.Stub throws PackageManagerException { final PackageAbiHelper packageAbiHelper = injector.getAbiHelper(); final UserManagerInternal userManager = injector.getUserManagerInternal(); - final PackageParser.Package pkg = request.pkg; + ParsedPackage parsedPackage = request.parsedPackage; PackageSetting pkgSetting = request.pkgSetting; final PackageSetting disabledPkgSetting = request.disabledPkgSetting; final PackageSetting originalPkgSetting = request.originalPkgSetting; @@ -10717,13 +10680,12 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_PACKAGE_SCANNING) { if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) - Log.d(TAG, "Scanning package " + pkg.packageName); + Log.d(TAG, "Scanning package " + parsedPackage.getPackageName()); } // Initialize package source and resource directories - final File scanFile = new File(pkg.codePath); - final File destCodeFile = new File(pkg.applicationInfo.getCodePath()); - final File destResourceFile = new File(pkg.applicationInfo.getResourcePath()); + final File destCodeFile = new File(parsedPackage.getAppInfoCodePath()); + final File destResourceFile = new File(parsedPackage.getAppInfoResourcePath()); // We keep references to the derived CPU Abis from settings in oder to reuse // them in the case where we're not upgrading or booting for the first time. @@ -10742,7 +10704,7 @@ public class PackageManagerService extends IPackageManager.Stub if (pkgSetting != null && pkgSetting.sharedUser != sharedUserSetting) { PackageManagerService.reportSettingsProblem(Log.WARN, - "Package " + pkg.packageName + " shared user changed from " + "Package " + parsedPackage.getPackageName() + " shared user changed from " + (pkgSetting.sharedUser != null ? pkgSetting.sharedUser.name : "<nothing>") + " to " @@ -10752,30 +10714,28 @@ public class PackageManagerService extends IPackageManager.Stub } String[] usesStaticLibraries = null; - if (pkg.usesStaticLibraries != null) { - usesStaticLibraries = new String[pkg.usesStaticLibraries.size()]; - pkg.usesStaticLibraries.toArray(usesStaticLibraries); + if (parsedPackage.getUsesStaticLibraries() != null) { + usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()]; + parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries); } final boolean createNewPackage = (pkgSetting == null); if (createNewPackage) { - final String parentPackageName = (pkg.parentPackage != null) - ? pkg.parentPackage.packageName : null; final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0; // REMOVE SharedUserSetting from method; update in a separate call - pkgSetting = Settings.createNewSetting(pkg.packageName, originalPkgSetting, - disabledPkgSetting, realPkgName, sharedUserSetting, destCodeFile, - destResourceFile, pkg.applicationInfo.nativeLibraryRootDir, - pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi, - pkg.mVersionCode, pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, - user, true /*allowInstall*/, instantApp, virtualPreload, - parentPackageName, pkg.getChildPackageNames(), - UserManagerService.getInstance(), usesStaticLibraries, - pkg.usesStaticLibrariesVersions); + pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(), + originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting, + destCodeFile, destResourceFile, parsedPackage.getNativeLibraryRootDir(), + parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(), + parsedPackage.getVersionCode(), parsedPackage.getFlags(), + parsedPackage.getPrivateFlags(), user, true /*allowInstall*/, instantApp, + virtualPreload, UserManagerService.getInstance(), usesStaticLibraries, + parsedPackage.getUsesStaticLibrariesVersions()); } else { // make a deep copy to avoid modifying any existing system state. pkgSetting = new PackageSetting(pkgSetting); - pkgSetting.pkg = pkg; + // TODO(b/135203078): Remove entirely. Set package directly. + parsedPackage.setPackageSettingCallback(pkgSetting); // REMOVE SharedUserSetting from method; update in a separate call. // @@ -10783,18 +10743,18 @@ public class PackageManagerService extends IPackageManager.Stub // secondaryCpuAbi are not known at this point so we always update them // to null here, only to reset them at a later point. Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting, - destCodeFile, destResourceFile, pkg.applicationInfo.nativeLibraryDir, - pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi, - pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, - pkg.getChildPackageNames(), UserManagerService.getInstance(), - usesStaticLibraries, pkg.usesStaticLibrariesVersions); + destCodeFile, destResourceFile, parsedPackage.getNativeLibraryDir(), + parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(), + parsedPackage.getFlags(), parsedPackage.getPrivateFlags(), + UserManagerService.getInstance(), + usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions()); } if (createNewPackage && originalPkgSetting != null) { // This is the initial transition from the original package, so, // fix up the new package's name now. We must do this after looking // up the package under its new name, so getPackageLP takes care of // fiddling things correctly. - pkg.setPackageName(originalPkgSetting.name); + parsedPackage.setPackageName(originalPkgSetting.name); // File a report about this. String msg = "New package " + pkgSetting.realName @@ -10813,68 +10773,69 @@ public class PackageManagerService extends IPackageManager.Stub if (disabledPkgSetting != null || (0 != (scanFlags & SCAN_NEW_INSTALL) && pkgSetting != null && pkgSetting.isSystem())) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + parsedPackage.mutate().setUpdatedSystemApp(true); } - pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, sharedUserSetting, - injector.getCompatibility()); - pkg.applicationInfo.seInfoUser = SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState( - userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)); - - pkg.mExtras = pkgSetting; - pkg.applicationInfo.processName = fixProcessName( - pkg.applicationInfo.packageName, - pkg.applicationInfo.processName); + parsedPackage + .setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting, + injector.getCompatibility())) + .setSeInfoUser(SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState( + userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId))) + .setProcessName(fixProcessName(parsedPackage.getPackageName(), + parsedPackage.getProcessName())); if (!isPlatformPackage) { // Get all of our default paths setup - pkg.applicationInfo.initForUser(UserHandle.USER_SYSTEM); + parsedPackage.initForUser(UserHandle.USER_SYSTEM); } - if (pkg.isSystem()) { - configurePackageComponents(pkg); + if (parsedPackage.isSystem()) { + configurePackageComponents(parsedPackage); } - final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting); + final String cpuAbiOverride = deriveAbiOverride(parsedPackage.getCpuAbiOverride(), + pkgSetting); if ((scanFlags & SCAN_NEW_INSTALL) == 0) { if (needToDeriveAbi) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi"); - final boolean extractNativeLibs = !pkg.isLibrary(); + final boolean extractNativeLibs = !parsedPackage.isLibrary(); final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi = - packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs); - derivedAbi.first.applyTo(pkg); - derivedAbi.second.applyTo(pkg); + packageAbiHelper.derivePackageAbi(parsedPackage, cpuAbiOverride, + extractNativeLibs); + derivedAbi.first.applyTo(parsedPackage); + derivedAbi.second.applyTo(parsedPackage); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); // Some system apps still use directory structure for native libraries // in which case we might end up not detecting abi solely based on apk // structure. Try to detect abi based on directory structure. - if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() && - pkg.applicationInfo.primaryCpuAbi == null) { + if (isSystemApp(parsedPackage) && !parsedPackage.isUpdatedSystemApp() && + parsedPackage.getPrimaryCpuAbi() == null) { final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis( - pkg); - abis.applyTo(pkg); + parsedPackage); + abis.applyTo(parsedPackage); abis.applyTo(pkgSetting); final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = - packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir); - nativeLibraryPaths.applyTo(pkg); + packageAbiHelper.getNativeLibraryPaths(parsedPackage, + sAppLib32InstallDir); + nativeLibraryPaths.applyTo(parsedPackage); } } else { // This is not a first boot or an upgrade, don't bother deriving the // ABI during the scan. Instead, trust the value that was stored in the // package setting. - pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings; - pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings; + parsedPackage.setPrimaryCpuAbi(primaryCpuAbiFromSettings) + .setSecondaryCpuAbi(secondaryCpuAbiFromSettings); final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = - packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir); - nativeLibraryPaths.applyTo(pkg); + packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir); + nativeLibraryPaths.applyTo(parsedPackage); if (DEBUG_ABI_SELECTION) { Slog.i(TAG, "Using ABIS and native lib paths from settings : " + - pkg.packageName + " " + pkg.applicationInfo.primaryCpuAbi + ", " + - pkg.applicationInfo.secondaryCpuAbi); + parsedPackage.getPackageName() + " " + parsedPackage.getPrimaryCpuAbi() + + ", " + parsedPackage.getSecondaryCpuAbi()); } } } else { @@ -10882,8 +10843,8 @@ public class PackageManagerService extends IPackageManager.Stub // We haven't run dex-opt for this move (since we've moved the compiled output too) // but we already have this packages package info in the PackageSetting. We just // use that and derive the native library path based on the new codepath. - pkg.applicationInfo.primaryCpuAbi = pkgSetting.primaryCpuAbiString; - pkg.applicationInfo.secondaryCpuAbi = pkgSetting.secondaryCpuAbiString; + parsedPackage.setPrimaryCpuAbi(pkgSetting.primaryCpuAbiString) + .setSecondaryCpuAbi(pkgSetting.secondaryCpuAbiString); } // Set native library paths again. For moves, the path will be updated based on the @@ -10891,8 +10852,8 @@ public class PackageManagerService extends IPackageManager.Stub // ABIs we determined during compilation, but the path will depend on the final // package path (after the rename away from the stage path). final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = - packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir); - nativeLibraryPaths.applyTo(pkg); + packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir); + nativeLibraryPaths.applyTo(parsedPackage); } // This is a special case for the "system" package, where the ABI is @@ -10900,8 +10861,8 @@ public class PackageManagerService extends IPackageManager.Stub // of this ABI so that we can deal with "normal" applications that run under // the same UID correctly. if (isPlatformPackage) { - pkg.applicationInfo.primaryCpuAbi = VMRuntime.getRuntime().is64Bit() ? - Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]; + parsedPackage.setPrimaryCpuAbi(VMRuntime.getRuntime().is64Bit() ? + Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]); } // If there's a mismatch between the abi-override in the package setting @@ -10909,34 +10870,34 @@ public class PackageManagerService extends IPackageManager.Stub // would've already compiled the app without taking the package setting into // account. if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) { - if (cpuAbiOverride == null && pkg.packageName != null) { + if (cpuAbiOverride == null && parsedPackage.getPackageName() != null) { Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride + - " for package " + pkg.packageName); + " for package " + parsedPackage.getPackageName()); } } - pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi; - pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi; + pkgSetting.primaryCpuAbiString = parsedPackage.getPrimaryCpuAbi(); + pkgSetting.secondaryCpuAbiString = parsedPackage.getSecondaryCpuAbi(); pkgSetting.cpuAbiOverrideString = cpuAbiOverride; // Copy the derived override back to the parsed package, so that we can // update the package settings accordingly. - pkg.cpuAbiOverride = cpuAbiOverride; + parsedPackage.setCpuAbiOverride(cpuAbiOverride); if (DEBUG_ABI_SELECTION) { - Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.packageName - + " to root=" + pkg.applicationInfo.nativeLibraryRootDir + ", isa=" - + pkg.applicationInfo.nativeLibraryRootRequiresIsa); + Slog.d(TAG, "Resolved nativeLibraryRoot for " + parsedPackage.getPackageName() + + " to root=" + parsedPackage.getNativeLibraryRootDir() + ", isa=" + + parsedPackage.isNativeLibraryRootRequiresIsa()); } // Push the derived path down into PackageSettings so we know what to // clean up at uninstall time. - pkgSetting.legacyNativeLibraryPathString = pkg.applicationInfo.nativeLibraryRootDir; + pkgSetting.legacyNativeLibraryPathString = parsedPackage.getNativeLibraryRootDir(); if (DEBUG_ABI_SELECTION) { - Log.d(TAG, "Abis for package[" + pkg.packageName + "] are" + - " primary=" + pkg.applicationInfo.primaryCpuAbi + - " secondary=" + pkg.applicationInfo.secondaryCpuAbi); + Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are" + + " primary=" + parsedPackage.getPrimaryCpuAbi() + + " secondary=" + parsedPackage.getSecondaryCpuAbi()); } if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) { @@ -10946,22 +10907,20 @@ public class PackageManagerService extends IPackageManager.Stub // We also do this *before* we perform dexopt on this package, so that // we can avoid redundant dexopts, and also to make sure we've got the // code and package path correct. - changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, pkg, + changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, parsedPackage, packageAbiHelper.getAdjustedAbiForSharedUser( - pkgSetting.sharedUser.packages, pkg)); + pkgSetting.sharedUser.packages, parsedPackage)); } - if (isUnderFactoryTest && pkg.requestedPermissions.contains( - android.Manifest.permission.FACTORY_TEST)) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST; - } + parsedPackage.setFactoryTest(isUnderFactoryTest && parsedPackage.getRequestedPermissions() + .contains(android.Manifest.permission.FACTORY_TEST)); - if (isSystemApp(pkg)) { + if (parsedPackage.isSystem()) { pkgSetting.setIsOrphaned(true); } // Take care of first install / last update times. - final long scanFileTime = getLastModifiedTime(pkg); + final long scanFileTime = getLastModifiedTime(parsedPackage); if (currentTime != 0) { if (pkgSetting.firstInstallTime == 0) { pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime; @@ -10979,32 +10938,33 @@ public class PackageManagerService extends IPackageManager.Stub } } pkgSetting.setTimeStamp(scanFileTime); - - pkgSetting.pkg = pkg; - pkgSetting.pkgFlags = pkg.applicationInfo.flags; - if (pkg.getLongVersionCode() != pkgSetting.versionCode) { - pkgSetting.versionCode = pkg.getLongVersionCode(); + // TODO(b/135203078): Remove, move to constructor + parsedPackage.setPackageSettingCallback(pkgSetting); + pkgSetting.pkgFlags = parsedPackage.getFlags(); + if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) { + pkgSetting.versionCode = parsedPackage.getLongVersionCode(); } // Update volume if needed - final String volumeUuid = pkg.applicationInfo.volumeUuid; + final String volumeUuid = parsedPackage.getApplicationInfoVolumeUuid(); if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) { Slog.i(PackageManagerService.TAG, "Update" + (pkgSetting.isSystem() ? " system" : "") - + " package " + pkg.packageName + + " package " + parsedPackage.getPackageName() + " volume from " + pkgSetting.volumeUuid + " to " + volumeUuid); pkgSetting.volumeUuid = volumeUuid; } SharedLibraryInfo staticSharedLibraryInfo = null; - if (!TextUtils.isEmpty(pkg.staticSharedLibName)) { - staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(pkg); + if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) { + staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(parsedPackage); } List<SharedLibraryInfo> dynamicSharedLibraryInfos = null; - if (!ArrayUtils.isEmpty(pkg.libraryNames)) { - dynamicSharedLibraryInfos = new ArrayList<>(pkg.libraryNames.size()); - for (String name : pkg.libraryNames) { - dynamicSharedLibraryInfos.add(SharedLibraryInfo.createForDynamic(pkg, name)); + if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) { + dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size()); + for (String name : parsedPackage.getLibraryNames()) { + dynamicSharedLibraryInfos.add( + SharedLibraryInfo.createForDynamic(parsedPackage, name)); } } @@ -11040,22 +11000,21 @@ public class PackageManagerService extends IPackageManager.Stub * * @throws PackageManagerException If bytecode could not be found when it should exist */ - private static void assertCodePolicy(PackageParser.Package pkg) + private static void assertCodePolicy(AndroidPackage pkg) throws PackageManagerException { - final boolean shouldHaveCode = - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0; - if (shouldHaveCode && !apkHasCode(pkg.baseCodePath)) { + final boolean shouldHaveCode = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0; + if (shouldHaveCode && !apkHasCode(pkg.getBaseCodePath())) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, - "Package " + pkg.baseCodePath + " code is missing"); + "Package " + pkg.getBaseCodePath() + " code is missing"); } - if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { - for (int i = 0; i < pkg.splitCodePaths.length; i++) { + if (!ArrayUtils.isEmpty(pkg.getSplitCodePaths())) { + for (int i = 0; i < pkg.getSplitCodePaths().length; i++) { final boolean splitShouldHaveCode = - (pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0; - if (splitShouldHaveCode && !apkHasCode(pkg.splitCodePaths[i])) { + (pkg.getSplitFlags()[i] & ApplicationInfo.FLAG_HAS_CODE) != 0; + if (splitShouldHaveCode && !apkHasCode(pkg.getSplitCodePaths()[i])) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, - "Package " + pkg.splitCodePaths[i] + " code is missing"); + "Package " + pkg.getSplitCodePaths()[i] + " code is missing"); } } } @@ -11068,118 +11027,59 @@ public class PackageManagerService extends IPackageManager.Stub * Implementation detail: This method must NOT have any side effect. It would * ideally be static, but, it requires locks to read system state. */ - private static void applyPolicy(PackageParser.Package pkg, final @ParseFlags int parseFlags, - final @ScanFlags int scanFlags, PackageParser.Package platformPkg) { + private static void applyPolicy(ParsedPackage parsedPackage, final @ParseFlags int parseFlags, + final @ScanFlags int scanFlags, AndroidPackage platformPkg) { if ((scanFlags & SCAN_AS_SYSTEM) != 0) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; - if (pkg.applicationInfo.isDirectBootAware()) { - // we're direct boot aware; set for all components - for (PackageParser.Service s : pkg.services) { - s.info.directBootAware = true; - } - for (PackageParser.Provider p : pkg.providers) { - p.info.directBootAware = true; - } - for (PackageParser.Activity a : pkg.activities) { - a.info.directBootAware = true; - } - for (PackageParser.Activity r : pkg.receivers) { - r.info.directBootAware = true; - } + parsedPackage.setSystem(true); + // TODO(b/135203078): Can this be done in PackageParser? Or just inferred when the flag + // is set during parse. + if (parsedPackage.isDirectBootAware()) { + parsedPackage.setAllComponentsDirectBootAware(true); } - if (compressedFileExists(pkg.codePath)) { - pkg.isStub = true; + if (compressedFileExists(parsedPackage.getCodePath())) { + parsedPackage.setIsStub(true); } } else { - // non system apps can't be flagged as core - pkg.coreApp = false; - // clear flags not applicable to regular apps - pkg.applicationInfo.flags &= - ~ApplicationInfo.FLAG_PERSISTENT; - pkg.applicationInfo.privateFlags &= - ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE; - pkg.applicationInfo.privateFlags &= - ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; - // cap permission priorities - if (pkg.permissionGroups != null && pkg.permissionGroups.size() > 0) { - for (int i = pkg.permissionGroups.size() - 1; i >= 0; --i) { - pkg.permissionGroups.get(i).info.priority = 0; - } - } + parsedPackage + // non system apps can't be flagged as core + .setCoreApp(false) + // clear flags not applicable to regular apps + .setPersistent(false) + .setDefaultToDeviceProtectedStorage(false) + .setDirectBootAware(false) + // non system apps can't have permission priority + .capPermissionPriorities(); } if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) { - // clear protected broadcasts - pkg.protectedBroadcasts = null; - // ignore export request for single user receivers - if (pkg.receivers != null) { - for (int i = pkg.receivers.size() - 1; i >= 0; --i) { - final PackageParser.Activity receiver = pkg.receivers.get(i); - if ((receiver.info.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) { - receiver.info.exported = false; - } - } - } - // ignore export request for single user services - if (pkg.services != null) { - for (int i = pkg.services.size() - 1; i >= 0; --i) { - final PackageParser.Service service = pkg.services.get(i); - if ((service.info.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) { - service.info.exported = false; - } - } - } - // ignore export request for single user providers - if (pkg.providers != null) { - for (int i = pkg.providers.size() - 1; i >= 0; --i) { - final PackageParser.Provider provider = pkg.providers.get(i); - if ((provider.info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) { - provider.info.exported = false; - } - } - } + parsedPackage + .clearProtectedBroadcasts() + .markNotActivitiesAsNotExportedIfSingleUser(); } - if ((scanFlags & SCAN_AS_PRIVILEGED) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; - } - - if ((scanFlags & SCAN_AS_OEM) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM; - } - - if ((scanFlags & SCAN_AS_VENDOR) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR; - } - - if ((scanFlags & SCAN_AS_PRODUCT) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT; - } - - if ((scanFlags & SCAN_AS_SYSTEM_EXT) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT; - } - - if ((scanFlags & SCAN_AS_ODM) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ODM; - } + parsedPackage.setPrivileged((scanFlags & SCAN_AS_PRIVILEGED) != 0) + .setOem((scanFlags & SCAN_AS_OEM) != 0) + .setVendor((scanFlags & SCAN_AS_VENDOR) != 0) + .setProduct((scanFlags & SCAN_AS_PRODUCT) != 0) + .setSystemExt((scanFlags & SCAN_AS_SYSTEM_EXT) != 0) + .setOdm((scanFlags & SCAN_AS_ODM) != 0); // Check if the package is signed with the same key as the platform package. - if (PLATFORM_PACKAGE_NAME.equals(pkg.packageName) || - (platformPkg != null && compareSignatures( - platformPkg.mSigningDetails.signatures, - pkg.mSigningDetails.signatures) == PackageManager.SIGNATURE_MATCH)) { - pkg.applicationInfo.privateFlags |= - ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY; - } - - if (!isSystemApp(pkg)) { + parsedPackage.setSignedWithPlatformKey( + (PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName()) + || (platformPkg != null && compareSignatures( + platformPkg.getSigningDetails().signatures, + parsedPackage.getSigningDetails().signatures + ) == PackageManager.SIGNATURE_MATCH)) + ); + + if (!isSystemApp(parsedPackage)) { // Only system apps can use these features. - pkg.mOriginalPackages = null; - pkg.mRealPackage = null; - pkg.mAdoptPermissions = null; + parsedPackage.clearOriginalPackages() + .setRealPackage(null) + .clearAdoptPermissions(); } - PackageBackwardCompatibility.modifySharedLibraries(pkg); + PackageBackwardCompatibility.modifySharedLibraries(parsedPackage); } private static @NonNull <T> T assertNotNull(@Nullable T object, String message) @@ -11199,15 +11099,15 @@ public class PackageManagerService extends IPackageManager.Stub * * @throws PackageManagerException If the package fails any of the validation checks */ - private void assertPackageIsValid(PackageParser.Package pkg, final @ParseFlags int parseFlags, + private void assertPackageIsValid(AndroidPackage pkg, final @ParseFlags int parseFlags, final @ScanFlags int scanFlags) throws PackageManagerException { if ((parseFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) { assertCodePolicy(pkg); } - if (pkg.applicationInfo.getCodePath() == null || - pkg.applicationInfo.getResourcePath() == null) { + if (pkg.getAppInfoCodePath() == null || + pkg.getAppInfoResourcePath() == null) { // Bail out. The resource and code paths haven't been set. throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Code and resource paths haven't been set correctly"); @@ -11218,9 +11118,10 @@ public class PackageManagerService extends IPackageManager.Stub final boolean isUserInstall = (scanFlags & SCAN_BOOTING) == 0; final boolean isFirstBootOrUpgrade = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0; if ((isUserInstall || isFirstBootOrUpgrade) - && mApexManager.isApexPackage(pkg.packageName)) { + && mApexManager.isApexPackage(pkg.getPackageName())) { throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, - pkg.packageName + " is an APEX package and can't be installed as an APK."); + pkg.getPackageName() + + " is an APEX package and can't be installed as an APK."); } // Make sure we're not adding any bogus keyset info @@ -11229,11 +11130,11 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { // The special "android" package can only be defined once - if (pkg.packageName.equals("android")) { + if (pkg.getPackageName().equals("android")) { if (mAndroidApplication != null) { Slog.w(TAG, "*************************************************"); Slog.w(TAG, "Core android package being redefined. Skipping."); - Slog.w(TAG, " codePath=" + pkg.codePath); + Slog.w(TAG, " codePath=" + pkg.getCodePath()); Slog.w(TAG, "*************************************************"); throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, "Core android package being redefined. Skipping."); @@ -11241,23 +11142,24 @@ public class PackageManagerService extends IPackageManager.Stub } // A package name must be unique; don't allow duplicates - if ((scanFlags & SCAN_NEW_INSTALL) == 0 && mPackages.containsKey(pkg.packageName)) { + if ((scanFlags & SCAN_NEW_INSTALL) == 0 + && mPackages.containsKey(pkg.getPackageName())) { throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, - "Application package " + pkg.packageName + "Application package " + pkg.getPackageName() + " already installed. Skipping duplicate."); } - if (pkg.applicationInfo.isStaticSharedLibrary()) { + if (pkg.isStaticSharedLibrary()) { // Static libs have a synthetic package name containing the version // but we still want the base name to be unique. if ((scanFlags & SCAN_NEW_INSTALL) == 0 - && mPackages.containsKey(pkg.manifestPackageName)) { + && mPackages.containsKey(pkg.getManifestPackageName())) { throw new PackageManagerException( "Duplicate static shared lib provider package"); } // Static shared libraries should have at least O target SDK - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) { + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) { throw new PackageManagerException( "Packages declaring static-shared libs must target O SDK or higher"); } @@ -11270,73 +11172,67 @@ public class PackageManagerService extends IPackageManager.Stub // Package declaring static a shared lib cannot be renamed since the package // name is synthetic and apps can't code around package manager internals. - if (!ArrayUtils.isEmpty(pkg.mOriginalPackages)) { + if (!ArrayUtils.isEmpty(pkg.getOriginalPackages())) { throw new PackageManagerException( "Packages declaring static-shared libs cannot be renamed"); } - // Package declaring static a shared lib cannot declare child packages - if (!ArrayUtils.isEmpty(pkg.childPackages)) { - throw new PackageManagerException( - "Packages declaring static-shared libs cannot have child packages"); - } - // Package declaring static a shared lib cannot declare dynamic libs - if (!ArrayUtils.isEmpty(pkg.libraryNames)) { + if (!ArrayUtils.isEmpty(pkg.getLibraryNames())) { throw new PackageManagerException( "Packages declaring static-shared libs cannot declare dynamic libs"); } // Package declaring static a shared lib cannot declare shared users - if (pkg.mSharedUserId != null) { + if (pkg.getSharedUserId() != null) { throw new PackageManagerException( "Packages declaring static-shared libs cannot declare shared users"); } // Static shared libs cannot declare activities - if (!pkg.activities.isEmpty()) { + if (pkg.getActivities() != null && !pkg.getActivities().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare activities"); } // Static shared libs cannot declare services - if (!pkg.services.isEmpty()) { + if (pkg.getServices() != null && !pkg.getServices().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare services"); } // Static shared libs cannot declare providers - if (!pkg.providers.isEmpty()) { + if (pkg.getProviders() != null && !pkg.getProviders().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare content providers"); } // Static shared libs cannot declare receivers - if (!pkg.receivers.isEmpty()) { + if (pkg.getReceivers() != null && !pkg.getReceivers().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare broadcast receivers"); } // Static shared libs cannot declare permission groups - if (!pkg.permissionGroups.isEmpty()) { + if (pkg.getPermissionGroups() != null && !pkg.getPermissionGroups().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare permission groups"); } // Static shared libs cannot declare permissions - if (!pkg.permissions.isEmpty()) { + if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare permissions"); } // Static shared libs cannot declare protected broadcasts - if (pkg.protectedBroadcasts != null) { + if (pkg.getProtectedBroadcasts() != null) { throw new PackageManagerException( "Static shared libs cannot declare protected broadcasts"); } // Static shared libs cannot be overlay targets - if (pkg.mOverlayTarget != null) { + if (pkg.getOverlayTarget() != null) { throw new PackageManagerException( "Static shared libs cannot be overlay targets"); } @@ -11346,16 +11242,17 @@ public class PackageManagerService extends IPackageManager.Stub long maxVersionCode = Long.MAX_VALUE; LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get( - pkg.staticSharedLibName); + pkg.getStaticSharedLibName()); if (versionedLib != null) { final int versionCount = versionedLib.size(); for (int i = 0; i < versionCount; i++) { SharedLibraryInfo libInfo = versionedLib.valueAt(i); final long libVersionCode = libInfo.getDeclaringPackage() .getLongVersionCode(); - if (libInfo.getLongVersion() < pkg.staticSharedLibVersion) { + if (libInfo.getLongVersion() < pkg.getStaticSharedLibVersion()) { minVersionCode = Math.max(minVersionCode, libVersionCode + 1); - } else if (libInfo.getLongVersion() > pkg.staticSharedLibVersion) { + } else if (libInfo.getLongVersion() + > pkg.getStaticSharedLibVersion()) { maxVersionCode = Math.min(maxVersionCode, libVersionCode - 1); } else { minVersionCode = maxVersionCode = libVersionCode; @@ -11370,23 +11267,6 @@ public class PackageManagerService extends IPackageManager.Stub } } - // Only privileged apps and updated privileged apps can add child packages. - if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) { - if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) { - throw new PackageManagerException("Only privileged apps can add child " - + "packages. Ignoring package " + pkg.packageName); - } - final int childCount = pkg.childPackages.size(); - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - if (mSettings.hasOtherDisabledSystemPkgWithChildLPr(pkg.packageName, - childPkg.packageName)) { - throw new PackageManagerException("Can't override child of " - + "another disabled app. Ignoring package " + pkg.packageName); - } - } - } - // If we're only installing presumed-existing packages, require that the // scanned APK is both already known and at the path previously established // for it. Previously unknown packages we pick up normally, but if we have an @@ -11396,29 +11276,30 @@ public class PackageManagerService extends IPackageManager.Stub // to the user-installed location. If we don't allow this change, any newer, // user-installed version of the application will be ignored. if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) { - if (mExpectingBetter.containsKey(pkg.packageName)) { + if (mExpectingBetter.containsKey(pkg.getPackageName())) { logCriticalInfo(Log.WARN, - "Relax SCAN_REQUIRE_KNOWN requirement for package " + pkg.packageName); + "Relax SCAN_REQUIRE_KNOWN requirement for package " + + pkg.getPackageName()); } else { - PackageSetting known = mSettings.getPackageLPr(pkg.packageName); + PackageSetting known = mSettings.getPackageLPr(pkg.getPackageName()); if (known != null) { if (DEBUG_PACKAGE_SCANNING) { - Log.d(TAG, "Examining " + pkg.codePath + Log.d(TAG, "Examining " + pkg.getCodePath() + " and requiring known paths " + known.codePathString + " & " + known.resourcePathString); } - if (!pkg.applicationInfo.getCodePath().equals(known.codePathString) - || !pkg.applicationInfo.getResourcePath().equals( + if (!pkg.getAppInfoCodePath().equals(known.codePathString) + || !pkg.getAppInfoResourcePath().equals( known.resourcePathString)) { throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED, - "Application package " + pkg.packageName - + " found at " + pkg.applicationInfo.getCodePath() + "Application package " + pkg.getPackageName() + + " found at " + pkg.getAppInfoCodePath() + " but expected at " + known.codePathString + "; ignoring."); } } else { throw new PackageManagerException(INSTALL_FAILED_INVALID_INSTALL_LOCATION, - "Application package " + pkg.packageName + "Application package " + pkg.getPackageName() + " not found; ignoring."); } } @@ -11433,11 +11314,13 @@ public class PackageManagerService extends IPackageManager.Stub } // Verify that packages sharing a user with a privileged app are marked as privileged. - if (!pkg.isPrivileged() && (pkg.mSharedUserId != null)) { + if (!pkg.isPrivileged() && (pkg.getSharedUserId() != null)) { SharedUserSetting sharedUserSetting = null; try { - sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false); - } catch (PackageManagerException ignore) {} + sharedUserSetting = mSettings.getSharedUserLPw(pkg.getSharedUserId(), + 0, 0, false); + } catch (PackageManagerException ignore) { + } if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { // Exempt SharedUsers signed with the platform key. PackageSetting platformPkgSetting = mSettings.mPackages.get("android"); @@ -11445,18 +11328,18 @@ public class PackageManagerService extends IPackageManager.Stub != PackageParser.SigningDetails.UNKNOWN) && (compareSignatures( platformPkgSetting.signatures.mSigningDetails.signatures, - pkg.mSigningDetails.signatures) + pkg.getSigningDetails().signatures) != PackageManager.SIGNATURE_MATCH)) { throw new PackageManagerException("Apps that share a user with a " + "privileged app must themselves be marked as privileged. " + - pkg.packageName + " shares privileged user " + - pkg.mSharedUserId + "."); + pkg.getPackageName() + " shares privileged user " + + pkg.getSharedUserId() + "."); } } } // Apply policies specific for runtime resource overlays (RROs). - if (pkg.mOverlayTarget != null) { + if (pkg.getOverlayTarget() != null) { // System overlays have some restrictions on their use of the 'static' state. if ((scanFlags & SCAN_AS_SYSTEM) != 0) { // We are scanning a system overlay. This can be the first scan of the @@ -11464,54 +11347,62 @@ public class PackageManagerService extends IPackageManager.Stub if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { // This must be an update to a system overlay. final PackageSetting previousPkg = assertNotNull( - mSettings.getPackageLPr(pkg.packageName), + mSettings.getPackageLPr(pkg.getPackageName()), "previous package state not present"); // previousPkg.pkg may be null: the package will be not be scanned if the // package manager knows there is a newer version on /data. // TODO[b/79435695]: Find a better way to keep track of the "static" // property for RROs instead of having to parse packages on /system - PackageParser.Package ppkg = previousPkg.pkg; + AndroidPackage ppkg = previousPkg.pkg; if (ppkg == null) { try { final PackageParser pp = new PackageParser(); - ppkg = pp.parsePackage(previousPkg.codePath, - parseFlags | PackageParser.PARSE_IS_SYSTEM_DIR); + // TODO(b/135203078): Do we really need to parse here? Maybe use + // a shortened path? + ppkg = pp.parseParsedPackage(previousPkg.codePath, + parseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, + false) + .hideAsFinal(); } catch (PackageParserException e) { Slog.w(TAG, "failed to parse " + previousPkg.codePath, e); } } // Static overlays cannot be updated. - if (ppkg != null && ppkg.mOverlayIsStatic) { - throw new PackageManagerException("Overlay " + pkg.packageName + - " is static and cannot be upgraded."); + if (ppkg != null && ppkg.isOverlayIsStatic()) { + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + + " is static and cannot be upgraded."); // Non-static overlays cannot be converted to static overlays. - } else if (pkg.mOverlayIsStatic) { - throw new PackageManagerException("Overlay " + pkg.packageName + - " cannot be upgraded into a static overlay."); + } else if (pkg.isOverlayIsStatic()) { + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + + " cannot be upgraded into a static overlay."); } } } else { // The overlay is a non-system overlay. Non-system overlays cannot be static. - if (pkg.mOverlayIsStatic) { - throw new PackageManagerException("Overlay " + pkg.packageName + - " is static but not pre-installed."); + if (pkg.isOverlayIsStatic()) { + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + + " is static but not pre-installed."); } // A non-preloaded overlay packages must have targetSdkVersion >= Q, or be // signed with the platform certificate. Check this in increasing order of // computational cost. - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) { + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) { final PackageSetting platformPkgSetting = mSettings.getPackageLPr("android"); if ((platformPkgSetting.signatures.mSigningDetails != PackageParser.SigningDetails.UNKNOWN) && (compareSignatures( platformPkgSetting.signatures.mSigningDetails.signatures, - pkg.mSigningDetails.signatures) + pkg.getSigningDetails().signatures) != PackageManager.SIGNATURE_MATCH)) { - throw new PackageManagerException("Overlay " + pkg.packageName + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + " must target Q or later, " + "or be signed with the platform certificate"); } @@ -11521,18 +11412,19 @@ public class PackageManagerService extends IPackageManager.Stub // only be used if it is signed with the same certificate as its target. If the // target is already installed, check this here to augment the last line of // defence which is OMS. - if (pkg.mOverlayTargetName == null) { + if (pkg.getOverlayTargetName() == null) { final PackageSetting targetPkgSetting = - mSettings.getPackageLPr(pkg.mOverlayTarget); + mSettings.getPackageLPr(pkg.getOverlayTarget()); if (targetPkgSetting != null) { if ((targetPkgSetting.signatures.mSigningDetails != PackageParser.SigningDetails.UNKNOWN) && (compareSignatures( targetPkgSetting.signatures.mSigningDetails.signatures, - pkg.mSigningDetails.signatures) + pkg.getSigningDetails().signatures) != PackageManager.SIGNATURE_MATCH)) { - throw new PackageManagerException("Overlay " + pkg.packageName - + " and target " + pkg.mOverlayTarget + " signed with" + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + " and target " + + pkg.getOverlayTarget() + " signed with" + " different certificates, and the overlay lacks" + " <overlay android:targetName>"); } @@ -11612,71 +11504,67 @@ public class PackageManagerService extends IPackageManager.Stub * Adds a scanned package to the system. When this method is finished, the package will * be available for query, resolution, etc... */ - private void commitPackageSettings(PackageParser.Package pkg, - @Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting, + private void commitPackageSettings(AndroidPackage pkg, + @Nullable AndroidPackage oldPkg, PackageSetting pkgSetting, final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) { - final String pkgName = pkg.packageName; + final String pkgName = pkg.getPackageName(); if (mCustomResolverComponentName != null && - mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) { + mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) { setUpCustomResolverActivity(pkg); } - if (pkg.packageName.equals("android")) { + if (pkg.getPackageName().equals("android")) { synchronized (mLock) { - if ((scanFlags & SCAN_CHECK_ONLY) == 0) { - // Set up information for our fall-back user intent resolution activity. - mPlatformPackage = pkg; - pkg.mVersionCode = mSdkVersion; - pkg.mVersionCodeMajor = 0; - mAndroidApplication = pkg.applicationInfo; - if (!mResolverReplaced) { - mResolveActivity.applicationInfo = mAndroidApplication; - mResolveActivity.name = ResolverActivity.class.getName(); - mResolveActivity.packageName = mAndroidApplication.packageName; - mResolveActivity.processName = "system:ui"; - mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; - mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER; - mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; - mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert; - mResolveActivity.exported = true; - mResolveActivity.enabled = true; - mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; - mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE - | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE - | ActivityInfo.CONFIG_SCREEN_LAYOUT - | ActivityInfo.CONFIG_ORIENTATION - | ActivityInfo.CONFIG_KEYBOARD - | ActivityInfo.CONFIG_KEYBOARD_HIDDEN; - mResolveInfo.activityInfo = mResolveActivity; - mResolveInfo.priority = 0; - mResolveInfo.preferredOrder = 0; - mResolveInfo.match = 0; - mResolveComponentName = new ComponentName( - mAndroidApplication.packageName, mResolveActivity.name); - } - } - } - } - - ArrayList<PackageParser.Package> clientLibPkgs = null; + // Set up information for our fall-back user intent resolution activity. + mPlatformPackage = pkg; + mAndroidApplication = pkg.toAppInfoWithoutState(); + if (!mResolverReplaced) { + mResolveActivity.applicationInfo = mAndroidApplication; + mResolveActivity.name = ResolverActivity.class.getName(); + mResolveActivity.packageName = mAndroidApplication.packageName; + mResolveActivity.processName = "system:ui"; + mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; + mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER; + mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; + mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert; + mResolveActivity.exported = true; + mResolveActivity.enabled = true; + mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; + mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE + | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE + | ActivityInfo.CONFIG_SCREEN_LAYOUT + | ActivityInfo.CONFIG_ORIENTATION + | ActivityInfo.CONFIG_KEYBOARD + | ActivityInfo.CONFIG_KEYBOARD_HIDDEN; + mResolveInfo.activityInfo = mResolveActivity; + mResolveInfo.priority = 0; + mResolveInfo.preferredOrder = 0; + mResolveInfo.match = 0; + mResolveComponentName = new ComponentName( + mAndroidApplication.packageName, mResolveActivity.name); + } + } + } + + ArrayList<AndroidPackage> clientLibPkgs = null; // writer synchronized (mLock) { if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) { for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) { commitSharedLibraryInfoLocked(info); } - final Map<String, PackageParser.Package> combinedPackages = - reconciledPkg.getCombinedPackages(); + final Map<String, AndroidPackage> combinedSigningDetails = + reconciledPkg.getCombinedAvailablePackages(); try { // Shared libraries for the package need to be updated. - updateSharedLibrariesLocked(pkg, null, combinedPackages); + updateSharedLibrariesLocked(pkg, null, combinedSigningDetails); } catch (PackageManagerException e) { Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e); } // Update all applications that use this library. Skip when booting // since this will be done after all packages are scaned. if ((scanFlags & SCAN_BOOTING) == 0) { - clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedPackages); + clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedSigningDetails); } } } @@ -11700,9 +11588,9 @@ public class PackageManagerService extends IPackageManager.Stub // Also need to kill any apps that are dependent on the library. if (clientLibPkgs != null) { for (int i=0; i<clientLibPkgs.size(); i++) { - PackageParser.Package clientPkg = clientLibPkgs.get(i); - killApplication(clientPkg.applicationInfo.packageName, - clientPkg.applicationInfo.uid, "update lib"); + AndroidPackage clientPkg = clientLibPkgs.get(i); + killApplication(clientPkg.getAppInfoPackageName(), + clientPkg.getUid(), "update lib"); } } @@ -11715,7 +11603,7 @@ public class PackageManagerService extends IPackageManager.Stub // Add the new setting to mSettings mSettings.insertPackageSettingLPw(pkgSetting, pkg); // Add the new setting to mPackages - mPackages.put(pkg.applicationInfo.packageName, pkg); + mPackages.put(pkg.getAppInfoPackageName(), pkg); // Add the package's KeySets to the global KeySetManagerService KeySetManagerService ksms = mSettings.mKeySetManagerService; @@ -11726,7 +11614,7 @@ public class PackageManagerService extends IPackageManager.Stub // Don't allow ephemeral applications to define new permissions groups. if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { - Slog.w(TAG, "Permission groups from package " + pkg.packageName + Slog.w(TAG, "Permission groups from package " + pkg.getPackageName() + " ignored: instant apps cannot define new permission groups."); } else { mPermissionManager.addAllPermissionGroups(pkg, chatty); @@ -11734,31 +11622,18 @@ public class PackageManagerService extends IPackageManager.Stub // Don't allow ephemeral applications to define new permissions. if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { - Slog.w(TAG, "Permissions from package " + pkg.packageName + Slog.w(TAG, "Permissions from package " + pkg.getPackageName() + " ignored: instant apps cannot define new permissions."); } else { mPermissionManager.addAllPermissions(pkg, chatty); } - int collectionSize = pkg.instrumentation.size(); + int collectionSize = ArrayUtils.size(pkg.getInstrumentations()); StringBuilder r = null; int i; for (i = 0; i < collectionSize; i++) { - PackageParser.Instrumentation a = pkg.instrumentation.get(i); - a.info.packageName = pkg.applicationInfo.packageName; - a.info.sourceDir = pkg.applicationInfo.sourceDir; - a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir; - a.info.splitNames = pkg.splitNames; - a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs; - a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs; - a.info.splitDependencies = pkg.applicationInfo.splitDependencies; - a.info.dataDir = pkg.applicationInfo.dataDir; - a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir; - a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir; - a.info.primaryCpuAbi = pkg.applicationInfo.primaryCpuAbi; - a.info.secondaryCpuAbi = pkg.applicationInfo.secondaryCpuAbi; - a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir; - a.info.secondaryNativeLibraryDir = pkg.applicationInfo.secondaryNativeLibraryDir; + ParsedInstrumentation a = pkg.getInstrumentations().get(i); + a.setPackageName(pkg.getPackageName()); mInstrumentation.put(a.getComponentName(), a); if (chatty) { if (r == null) { @@ -11766,19 +11641,16 @@ public class PackageManagerService extends IPackageManager.Stub } else { r.append(' '); } - r.append(a.info.name); + r.append(a.getName()); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r); } - if (pkg.protectedBroadcasts != null) { - collectionSize = pkg.protectedBroadcasts.size(); + if (pkg.getProtectedBroadcasts() != null) { synchronized (mProtectedBroadcasts) { - for (i = 0; i < collectionSize; i++) { - mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i)); - } + mProtectedBroadcasts.addAll(pkg.getProtectedBroadcasts()); } } @@ -11802,14 +11674,14 @@ public class PackageManagerService extends IPackageManager.Stub Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } - private void setUpCustomResolverActivity(PackageParser.Package pkg) { + private void setUpCustomResolverActivity(AndroidPackage pkg) { synchronized (mLock) { mResolverReplaced = true; // Set up information for custom user intent resolution activity. - mResolveActivity.applicationInfo = pkg.applicationInfo; + mResolveActivity.applicationInfo = pkg.toAppInfoWithoutState(); mResolveActivity.name = mCustomResolverComponentName.getClassName(); - mResolveActivity.packageName = pkg.applicationInfo.packageName; - mResolveActivity.processName = pkg.applicationInfo.packageName; + mResolveActivity.packageName = pkg.getAppInfoPackageName(); + mResolveActivity.processName = pkg.getAppInfoProcessName(); mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; @@ -11876,22 +11748,13 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void removePackageLI(PackageParser.Package pkg, boolean chatty) { + private void removePackageLI(AndroidPackage pkg, boolean chatty) { // Remove the parent package setting - PackageSetting ps = (PackageSetting) pkg.mExtras; + PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps != null) { removePackageLI(ps.name, chatty); } else if (DEBUG_REMOVE && chatty) { - Log.d(TAG, "Not removing package " + pkg.packageName + "; mExtras == null"); - } - // Remove the child package setting - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - ps = (PackageSetting) childPkg.mExtras; - if (ps != null) { - removePackageLI(ps.name, chatty); - } + Log.d(TAG, "Not removing package " + pkg.getPackageName() + "; mExtras == null"); } } @@ -11903,24 +11766,24 @@ public class PackageManagerService extends IPackageManager.Stub // writer synchronized (mLock) { - final PackageParser.Package removedPackage = mPackages.remove(packageName); + final AndroidPackage removedPackage = mPackages.remove(packageName); if (removedPackage != null) { cleanPackageDataStructuresLILPw(removedPackage, chatty); } } } - void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) { + void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) { mComponentResolver.removeAllComponents(pkg, chatty); - mAppsFilter.removePackage((PackageSetting) pkg.mExtras, + mAppsFilter.removePackage(getPackageSetting(pkg.getPackageName()), mInjector.getUserManagerInternal().getUserIds(), mSettings.mPackages); mPermissionManager.removeAllPermissions(pkg, chatty); - final int instrumentationSize = pkg.instrumentation.size(); + final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations()); StringBuilder r = null; int i; for (i = 0; i < instrumentationSize; i++) { - PackageParser.Instrumentation a = pkg.instrumentation.get(i); + ParsedInstrumentation a = pkg.getInstrumentations().get(i); mInstrumentation.remove(a.getComponentName()); if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -11928,7 +11791,7 @@ public class PackageManagerService extends IPackageManager.Stub } else { r.append(' '); } - r.append(a.info.name); + r.append(a.getName()); } } if (r != null) { @@ -11936,12 +11799,12 @@ public class PackageManagerService extends IPackageManager.Stub } r = null; - if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) { // Only system apps can hold shared libraries. - if (pkg.libraryNames != null) { - final int libraryNamesSize = pkg.libraryNames.size(); + if (pkg.getLibraryNames() != null) { + final int libraryNamesSize = pkg.getLibraryNames().size(); for (i = 0; i < libraryNamesSize; i++) { - String name = pkg.libraryNames.get(i); + String name = pkg.getLibraryNames().get(i); if (removeSharedLibraryLPw(name, 0)) { if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -11959,15 +11822,16 @@ public class PackageManagerService extends IPackageManager.Stub r = null; // Any package can hold static shared libraries. - if (pkg.staticSharedLibName != null) { - if (removeSharedLibraryLPw(pkg.staticSharedLibName, pkg.staticSharedLibVersion)) { + if (pkg.getStaticSharedLibName() != null) { + if (removeSharedLibraryLPw(pkg.getStaticSharedLibName(), + pkg.getStaticSharedLibVersion())) { if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } - r.append(pkg.staticSharedLibName); + r.append(pkg.getStaticSharedLibName()); } } } @@ -12308,11 +12172,11 @@ public class PackageManagerService extends IPackageManager.Stub // Cannot hide static shared libs as they are considered // a part of the using app (emulating static linking). Also // static libs are installed always on internal storage. - PackageParser.Package pkg = mPackages.get(packageName); - if (pkg != null && pkg.staticSharedLibName != null) { + AndroidPackage pkg = mPackages.get(packageName); + if (pkg != null && pkg.getStaticSharedLibName() != null) { Slog.w(TAG, "Cannot hide package: " + packageName + " providing static shared library: " - + pkg.staticSharedLibName); + + pkg.getStaticSharedLibName()); return false; } // Only allow protected packages to hide themselves. @@ -12358,17 +12222,17 @@ public class PackageManagerService extends IPackageManager.Stub if (pkgSetting == null || !pkgSetting.isSystem()) { return; } - PackageParser.Package pkg = pkgSetting.pkg; - if (pkg != null && pkg.applicationInfo != null) { - pkg.applicationInfo.hiddenUntilInstalled = hidden; + AndroidPackage pkg = pkgSetting.pkg; + if (pkg != null) { + pkg.mutate().setHiddenUntilInstalled(hidden); } final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName); if (disabledPs == null) { return; } pkg = disabledPs.pkg; - if (pkg != null && pkg.applicationInfo != null) { - pkg.applicationInfo.hiddenUntilInstalled = hidden; + if (pkg != null) { + pkg.mutate().setHiddenUntilInstalled(hidden); } } } @@ -12560,7 +12424,7 @@ public class PackageManagerService extends IPackageManager.Stub if (installed) { if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0 && pkgSetting.pkg != null) { - whiteListedPermissions = pkgSetting.pkg.requestedPermissions; + whiteListedPermissions = pkgSetting.pkg.getRequestedPermissions(); } mPermissionManager.setWhitelistedRestrictedPermissions(packageName, whiteListedPermissions, FLAG_PERMISSION_WHITELIST_INSTALLER, userId); @@ -12990,11 +12854,11 @@ public class PackageManagerService extends IPackageManager.Stub // Cannot suspend static shared libs as they are considered // a part of the using app (emulating static linking). Also // static libs are installed always on internal storage. - PackageParser.Package pkg = mPackages.get(packageName); - if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) { + AndroidPackage pkg = mPackages.get(packageName); + if (pkg != null && pkg.isStaticSharedLibrary()) { Slog.w(TAG, "Cannot suspend package: " + packageName + " providing static shared library: " - + pkg.staticSharedLibName); + + pkg.getStaticSharedLibName()); continue; } } @@ -13139,10 +13003,10 @@ public class PackageManagerService extends IPackageManager.Stub private int getUidForVerifier(VerifierInfo verifierInfo) { synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(verifierInfo.packageName); + final AndroidPackage pkg = mPackages.get(verifierInfo.packageName); if (pkg == null) { return -1; - } else if (pkg.mSigningDetails.signatures.length != 1) { + } else if (pkg.getSigningDetails().signatures.length != 1) { Slog.i(TAG, "Verifier package " + verifierInfo.packageName + " has more than one signature; ignoring"); return -1; @@ -13156,7 +13020,7 @@ public class PackageManagerService extends IPackageManager.Stub final byte[] expectedPublicKey; try { - final Signature verifierSig = pkg.mSigningDetails.signatures[0]; + final Signature verifierSig = pkg.getSigningDetails().signatures[0]; final PublicKey publicKey = verifierSig.getPublicKey(); expectedPublicKey = publicKey.getEncoded(); } catch (CertificateException e) { @@ -13171,7 +13035,7 @@ public class PackageManagerService extends IPackageManager.Stub return -1; } - return pkg.applicationInfo.uid; + return pkg.getUid(); } } @@ -13347,26 +13211,33 @@ public class PackageManagerService extends IPackageManager.Stub final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); synchronized (mLock) { - PackageParser.Package pkg = mPackages.get(packageName); - if (pkg == null || pkg.activities == null) { + AndroidPackage pkg = mPackages.get(packageName); + if (pkg == null || ArrayUtils.isEmpty(pkg.getActivities())) { return ParceledListSlice.emptyList(); } - if (pkg.mExtras == null) { + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); + if (ps == null) { return ParceledListSlice.emptyList(); } - final PackageSetting ps = (PackageSetting) pkg.mExtras; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return ParceledListSlice.emptyList(); } - final int count = pkg.activities.size(); + final int count = ArrayUtils.size(pkg.getActivities()); ArrayList<IntentFilter> result = new ArrayList<>(); for (int n=0; n<count; n++) { - PackageParser.Activity activity = pkg.activities.get(n); + ParsedActivity activity = pkg.getActivities().get(n); if (activity.intents != null && activity.intents.size() > 0) { result.addAll(activity.intents); } } - return new ParceledListSlice<>(result); + return new ParceledListSlice<IntentFilter>(result) { + @Override + protected void writeElement(IntentFilter parcelable, Parcel dest, int callFlags) { + // IntentFilter has final Parcelable methods, so redirect to the subclass + ((ParsedActivityIntentInfo) parcelable).writeIntentInfoToParcel(dest, + callFlags); + } + }; } } @@ -13549,7 +13420,7 @@ public class PackageManagerService extends IPackageManager.Stub // package has not opted out of backup participation. final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null; - final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags; + final int flags = (res.pkg == null) ? 0 : res.pkg.getFlags(); boolean doRestore = !update && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0); @@ -13572,35 +13443,10 @@ public class PackageManagerService extends IPackageManager.Stub // restore if appropriate, then pass responsibility back to the // Package Manager to run the post-install observer callbacks // and broadcasts. - IBackupManager bm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - if (bm != null) { - // For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM - // in the BackupManager. USER_ALL is used in compatibility tests. - if (userId == UserHandle.USER_ALL) { - userId = UserHandle.USER_SYSTEM; - } - if (DEBUG_INSTALL) { - Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId); - } - Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token); - try { - if (bm.isBackupServiceActive(userId)) { - bm.restoreAtInstallForUser( - userId, res.pkg.applicationInfo.packageName, token); - } else { - doRestore = false; - } - } catch (RemoteException e) { - // can't happen; the backup manager is local - } catch (Exception e) { - Slog.e(TAG, "Exception trying to enqueue restore", e); - doRestore = false; - } - } else { - Slog.e(TAG, "Backup Manager not found!"); - doRestore = false; + if (res.freezer != null) { + res.freezer.close(); } + doRestore = performBackupManagerRestore(userId, token, res); } // If this is an update to a package that might be potentially downgraded, then we @@ -13609,42 +13455,7 @@ public class PackageManagerService extends IPackageManager.Stub // // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) { - IRollbackManager rm = IRollbackManager.Stub.asInterface( - ServiceManager.getService(Context.ROLLBACK_SERVICE)); - - final String packageName = res.pkg.applicationInfo.packageName; - final String seInfo = res.pkg.applicationInfo.seInfo; - final int[] allUsers = mUserManager.getUserIds(); - final int[] installedUsers; - - final PackageSetting ps; - int appId = -1; - long ceDataInode = -1; - synchronized (mSettings) { - ps = mSettings.getPackageLPr(packageName); - if (ps != null) { - appId = ps.appId; - ceDataInode = ps.getCeDataInode(userId); - } - - // NOTE: We ignore the user specified in the InstallParam because we know this is - // an update, and hence need to restore data for all installed users. - installedUsers = ps.queryInstalledUsers(allUsers, true); - } - - boolean doSnapshotOrRestore = data != null && data.args != null - && ((data.args.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0 - || (data.args.installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0); - - if (ps != null && doSnapshotOrRestore) { - try { - rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode, - seInfo, token); - } catch (RemoteException re) { - Log.e(TAG, "Error snapshotting/restoring user data: " + re); - } - doRestore = true; - } + doRestore = performRollbackManagerRestore(userId, token, res, data); } if (!doRestore) { @@ -13660,6 +13471,89 @@ public class PackageManagerService extends IPackageManager.Stub } /** + * Perform Backup Manager restore for a given {@link PackageInstalledInfo}. + * Returns whether the restore successfully completed. + */ + private boolean performBackupManagerRestore(int userId, int token, PackageInstalledInfo res) { + IBackupManager bm = IBackupManager.Stub.asInterface( + ServiceManager.getService(Context.BACKUP_SERVICE)); + if (bm != null) { + // For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM + // in the BackupManager. USER_ALL is used in compatibility tests. + if (userId == UserHandle.USER_ALL) { + userId = UserHandle.USER_SYSTEM; + } + if (DEBUG_INSTALL) { + Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId); + } + Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token); + try { + if (bm.isBackupServiceActive(userId)) { + bm.restoreAtInstallForUser( + userId, res.pkg.getAppInfoPackageName(), token); + } else { + return false; + } + } catch (RemoteException e) { + // can't happen; the backup manager is local + } catch (Exception e) { + Slog.e(TAG, "Exception trying to enqueue restore", e); + return false; + } + } else { + Slog.e(TAG, "Backup Manager not found!"); + return false; + } + return true; + } + + /** + * Perform Rollback Manager restore for a given {@link PackageInstalledInfo}. + * Returns whether the restore successfully completed. + */ + private boolean performRollbackManagerRestore(int userId, int token, PackageInstalledInfo res, + PostInstallData data) { + IRollbackManager rm = IRollbackManager.Stub.asInterface( + ServiceManager.getService(Context.ROLLBACK_SERVICE)); + + final String packageName = res.pkg.getAppInfoPackageName(); + final String seInfo = res.pkg.getSeInfo(); + final int[] allUsers = mUserManager.getUserIds(); + final int[] installedUsers; + + final PackageSetting ps; + int appId = -1; + long ceDataInode = -1; + synchronized (mSettings) { + ps = mSettings.getPackageLPr(packageName); + if (ps != null) { + appId = ps.appId; + ceDataInode = ps.getCeDataInode(userId); + } + + // NOTE: We ignore the user specified in the InstallParam because we know this is + // an update, and hence need to restore data for all installed users. + installedUsers = ps.queryInstalledUsers(allUsers, true); + } + + boolean doSnapshotOrRestore = data != null && data.args != null + && ((data.args.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0 + || (data.args.installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0); + + if (ps != null && doSnapshotOrRestore) { + try { + rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode, + seInfo, token); + } catch (RemoteException re) { + Log.e(TAG, "Error snapshotting/restoring user data: " + re); + return false; + } + return true; + } + return false; + } + + /** * Callback from PackageSettings whenever an app is first transitioned out of the * 'stopped' state. Normally we just issue the broadcast, but we can't do that if * the app was "launched" for a restoreAtInstall operation. Therefore we check @@ -13682,7 +13576,7 @@ public class PackageManagerService extends IPackageManager.Stub if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) { continue; } - if (packageName.equals(data.res.pkg.applicationInfo.packageName)) { + if (packageName.equals(data.res.pkg.getAppInfoPackageName())) { // right package; but is it for the right user? for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) { if (userId == data.res.newUsers[uIndex]) { @@ -14025,12 +13919,12 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { // Currently installed package which the new package is attempting to replace or // null if no such package is installed. - PackageParser.Package installedPkg = mPackages.get(packageName); + AndroidPackage installedPkg = mPackages.get(packageName); // Package which currently owns the data which the new package will own if installed. // If an app is unstalled while keeping data (e.g., adb uninstall -k), installedPkg // will be null whereas dataOwnerPkg will contain information about the package // which was uninstalled while keeping its data. - PackageParser.Package dataOwnerPkg = installedPkg; + AndroidPackage dataOwnerPkg = installedPkg; if (dataOwnerPkg == null) { PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { @@ -14057,7 +13951,7 @@ public class PackageManagerService extends IPackageManager.Stub if (dataOwnerPkg != null) { if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags, - dataOwnerPkg.applicationInfo.flags)) { + dataOwnerPkg.getFlags())) { try { checkDowngrade(dataOwnerPkg, pkgLite); } catch (PackageManagerException e) { @@ -14070,7 +13964,7 @@ public class PackageManagerService extends IPackageManager.Stub if (installedPkg != null) { if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { // Check for updated system application. - if ((installedPkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + if ((installedPkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) { return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } else { // If current upgrade specifies particular preference @@ -14543,7 +14437,7 @@ public class PackageManagerService extends IPackageManager.Stub * Rename package into final resting place. All paths on the given * scanned package should be updated to reflect the rename. */ - abstract boolean doRename(int status, PackageParser.Package pkg); + abstract boolean doRename(int status, ParsedPackage parsedPackage); abstract int doPostInstall(int status, int uid); /** @see PackageSettingBase#codePathString */ @@ -14687,7 +14581,8 @@ public class PackageManagerService extends IPackageManager.Stub return status; } - boolean doRename(int status, PackageParser.Package pkg) { + @Override + boolean doRename(int status, ParsedPackage parsedPackage) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(); return false; @@ -14695,7 +14590,7 @@ public class PackageManagerService extends IPackageManager.Stub final File targetDir = codeFile.getParentFile(); final File beforeCodeFile = codeFile; - final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName); + final File afterCodeFile = getNextCodePath(targetDir, parsedPackage.getPackageName()); if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile); final boolean onIncremental = mIncrementalManager != null @@ -14723,24 +14618,23 @@ public class PackageManagerService extends IPackageManager.Stub // Reflect the rename in scanned details try { - pkg.setCodePath(afterCodeFile.getCanonicalPath()); + parsedPackage.setCodePath(afterCodeFile.getCanonicalPath()); } catch (IOException e) { Slog.e(TAG, "Failed to get path: " + afterCodeFile, e); return false; } - pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile, - afterCodeFile, pkg.baseCodePath)); - pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile, - afterCodeFile, pkg.splitCodePaths)); + parsedPackage.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile, + afterCodeFile, parsedPackage.getBaseCodePath())); + parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile, + afterCodeFile, parsedPackage.getSplitCodePaths())); // Reflect the rename in app info - pkg.setApplicationVolumeUuid(pkg.volumeUuid); - pkg.setApplicationInfoCodePath(pkg.codePath); - pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath); - pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths); - pkg.setApplicationInfoResourcePath(pkg.codePath); - pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath); - pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths); + // TODO(b/135203078): Remove all of these application info calls + parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid()) + .setApplicationInfoCodePath(parsedPackage.getCodePath()) + .setApplicationInfoResourcePath(parsedPackage.getCodePath()) + .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath()) + .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths()); return true; } @@ -14843,20 +14737,20 @@ public class PackageManagerService extends IPackageManager.Stub return status; } - boolean doRename(int status, PackageParser.Package pkg) { + @Override + boolean doRename(int status, ParsedPackage parsedPackage) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(move.toUuid); return false; } // Reflect the move in app info - pkg.setApplicationVolumeUuid(pkg.volumeUuid); - pkg.setApplicationInfoCodePath(pkg.codePath); - pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath); - pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths); - pkg.setApplicationInfoResourcePath(pkg.codePath); - pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath); - pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths); + // TODO(b/135203078): Remove all of these application info calls + parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid()) + .setApplicationInfoCodePath(parsedPackage.getCodePath()) + .setApplicationInfoResourcePath(parsedPackage.getCodePath()) + .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath()) + .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths()); return true; } @@ -14932,14 +14826,15 @@ public class PackageManagerService extends IPackageManager.Stub int[] origUsers; // The set of users that now have this package installed. int[] newUsers; - PackageParser.Package pkg; + AndroidPackage pkg; int returnCode; String returnMsg; String installerPackageName; PackageRemovedInfo removedInfo; ArrayMap<String, PackageInstalledInfo> addedChildPackages; // The set of packages consuming this shared library or null if no consumers exist. - ArrayList<PackageParser.Package> libraryConsumers; + ArrayList<AndroidPackage> libraryConsumers; + PackageFreezer freezer; public void setError(int code, String msg) { setReturnCode(code); @@ -14995,107 +14890,37 @@ public class PackageManagerService extends IPackageManager.Stub } } - /** - * Checks whether the parent or any of the child packages have a change shared - * user. For a package to be a valid update the shred users of the parent and - * the children should match. We may later support changing child shared users. - * @param oldPkg The updated package. - * @param newPkg The update package. - * @return The shared user that change between the versions. - */ - private String getParentOrChildPackageChangedSharedUser(PackageParser.Package oldPkg, - PackageParser.Package newPkg) { - // Check parent shared user - if (!Objects.equals(oldPkg.mSharedUserId, newPkg.mSharedUserId)) { - return newPkg.packageName; - } - // Check child shared users - final int oldChildCount = (oldPkg.childPackages != null) ? oldPkg.childPackages.size() : 0; - final int newChildCount = (newPkg.childPackages != null) ? newPkg.childPackages.size() : 0; - for (int i = 0; i < newChildCount; i++) { - PackageParser.Package newChildPkg = newPkg.childPackages.get(i); - // If this child was present, did it have the same shared user? - for (int j = 0; j < oldChildCount; j++) { - PackageParser.Package oldChildPkg = oldPkg.childPackages.get(j); - if (newChildPkg.packageName.equals(oldChildPkg.packageName) - && !Objects.equals(newChildPkg.mSharedUserId, oldChildPkg.mSharedUserId)) { - return newChildPkg.packageName; - } - } - } - return null; - } - private void removeNativeBinariesLI(PackageSetting ps) { - // Remove the lib path for the parent package if (ps != null) { NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString); - // Remove the lib path for the child packages - final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageSetting childPs = null; - synchronized (mLock) { - childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i)); - } - if (childPs != null) { - NativeLibraryHelper.removeNativeBinariesLI(childPs - .legacyNativeLibraryPathString); - } - } } } @GuardedBy("mLock") - private void enableSystemPackageLPw(PackageParser.Package pkg) { - // Enable the parent package - mSettings.enableSystemPackageLPw(pkg.packageName); - // Enable the child packages - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - mSettings.enableSystemPackageLPw(childPkg.packageName); - } + private void enableSystemPackageLPw(AndroidPackage pkg) { + mSettings.enableSystemPackageLPw(pkg.getPackageName()); } @GuardedBy("mLock") - private boolean disableSystemPackageLPw(PackageParser.Package oldPkg, - PackageParser.Package newPkg) { - // Disable the parent package (parent always replaced) - boolean disabled = mSettings.disableSystemPackageLPw(oldPkg.packageName, true); - // Disable the child packages - final int childCount = (oldPkg.childPackages != null) ? oldPkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = oldPkg.childPackages.get(i); - final boolean replace = newPkg.hasChildPackage(childPkg.packageName); - disabled |= mSettings.disableSystemPackageLPw(childPkg.packageName, replace); - } - return disabled; - } - - private void updateSettingsLI(PackageParser.Package newPackage, - InstallArgs installArgs, int[] allUsers, PackageInstalledInfo res) { - // Update the parent package setting + private boolean disableSystemPackageLPw(AndroidPackage oldPkg) { + return mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true); + } + + private void updateSettingsLI(AndroidPackage newPackage, InstallArgs installArgs, + int[] allUsers, PackageInstalledInfo res) { updateSettingsInternalLI(newPackage, installArgs, allUsers, res); - // Update the child packages setting - final int childCount = (newPackage.childPackages != null) - ? newPackage.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPackage = newPackage.childPackages.get(i); - PackageInstalledInfo childRes = res.addedChildPackages.get(childPackage.packageName); - updateSettingsInternalLI(childPackage, installArgs, allUsers, childRes); - } } - private void updateSettingsInternalLI(PackageParser.Package pkg, - InstallArgs installArgs, int[] allUsers, PackageInstalledInfo res) { + private void updateSettingsInternalLI(AndroidPackage pkg, InstallArgs installArgs, + int[] allUsers, PackageInstalledInfo res) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings"); - final String pkgName = pkg.packageName; + final String pkgName = pkg.getPackageName(); final String installerPackageName = installArgs.installSource.installerPackageName; final int[] installedForUsers = res.origUsers; final int installReason = installArgs.installReason; - if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath); + if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getCodePath()); synchronized (mLock) { // NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions mPermissionManager.updatePermissions(pkgName, pkg); @@ -15168,7 +14993,7 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writeKernelMappingLPr(ps); } res.name = pkgName; - res.uid = pkg.applicationInfo.uid; + res.uid = pkg.getUid(); res.pkg = pkg; mSettings.setInstallerPackageName(pkgName, installerPackageName); res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); @@ -15226,7 +15051,7 @@ public class PackageManagerService extends IPackageManager.Stub private static class ReconcileRequest { public final Map<String, ScanResult> scannedPackages; - public final Map<String, PackageParser.Package> allPackages; + public final Map<String, AndroidPackage> allPackages; public final Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource; public final Map<String, InstallArgs> installArgs; public final Map<String, PackageInstalledInfo> installResults; @@ -15239,7 +15064,7 @@ public class PackageManagerService extends IPackageManager.Stub Map<String, PackageInstalledInfo> installResults, Map<String, PrepareResult> preparedPackages, Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource, - Map<String, PackageParser.Package> allPackages, + Map<String, AndroidPackage> allPackages, Map<String, VersionInfo> versionInfos, Map<String, PackageSetting> lastStaticSharedLibSettings) { this.scannedPackages = scannedPackages; @@ -15254,7 +15079,7 @@ public class PackageManagerService extends IPackageManager.Stub private ReconcileRequest(Map<String, ScanResult> scannedPackages, Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource, - Map<String, PackageParser.Package> allPackages, + Map<String, AndroidPackage> allPackages, Map<String, VersionInfo> versionInfos, Map<String, PackageSetting> lastStaticSharedLibSettings) { this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(), @@ -15322,15 +15147,17 @@ public class PackageManagerService extends IPackageManager.Stub * with the package(s) currently being installed. The to-be installed packages take * precedence and may shadow already installed packages. */ - private Map<String, PackageParser.Package> getCombinedPackages() { - final ArrayMap<String, PackageParser.Package> combinedPackages = + private Map<String, AndroidPackage> getCombinedAvailablePackages() { + final ArrayMap<String, AndroidPackage> combined = new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size()); - combinedPackages.putAll(request.allPackages); + combined.putAll(request.allPackages); + for (ScanResult scanResult : request.scannedPackages.values()) { - combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg); + combined.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage); } - return combinedPackages; + + return combined; } } @@ -15343,8 +15170,9 @@ public class PackageManagerService extends IPackageManager.Stub final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size()); // make a copy of the existing set of packages so we can combine them with incoming packages - final ArrayMap<String, PackageParser.Package> combinedPackages = + final ArrayMap<String, AndroidPackage> combinedPackages = new ArrayMap<>(request.allPackages.size() + scannedPackages.size()); + combinedPackages.putAll(request.allPackages); final Map<String, LongSparseArray<SharedLibraryInfo>> incomingSharedLibraries = @@ -15354,7 +15182,7 @@ public class PackageManagerService extends IPackageManager.Stub final ScanResult scanResult = scannedPackages.get(installPackageName); // add / replace existing with incoming packages - combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg); + combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage); // in the first pass, we'll build up the set of incoming shared libraries final List<SharedLibraryInfo> allowedSharedLibInfos = @@ -15387,7 +15215,7 @@ public class PackageManagerService extends IPackageManager.Stub | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP); deletePackageAction = mayDeletePackageLocked(res.removedInfo, prepareResult.originalPs, prepareResult.disabledPs, - prepareResult.childPackageSettings, deleteFlags, null /* all users */); + deleteFlags, null /* all users */); if (deletePackageAction == null) { throw new ReconcileFailure( PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE, @@ -15399,7 +15227,7 @@ public class PackageManagerService extends IPackageManager.Stub final int scanFlags = scanResult.request.scanFlags; final int parseFlags = scanResult.request.parseFlags; - final PackageParser.Package pkg = scanResult.request.pkg; + final ParsedPackage parsedPackage = scanResult.request.parsedPackage; final PackageSetting disabledPkgSetting = scanResult.request.disabledPkgSetting; final PackageSetting lastStaticSharedLibSetting = @@ -15412,35 +15240,37 @@ public class PackageManagerService extends IPackageManager.Stub boolean sharedUserSignaturesChanged = false; SigningDetails signingDetails = null; if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) { - if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) { + if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) { // We just determined the app is signed correctly, so bring // over the latest parsed certs. } else { if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, - "Package " + pkg.packageName + " upgrade keys do not match the " - + "previously installed version"); + "Package " + parsedPackage.getPackageName() + + " upgrade keys do not match the previously installed" + + " version"); } else { - String msg = "System package " + pkg.packageName + String msg = "System package " + parsedPackage.getPackageName() + " signature changed; retaining data."; reportSettingsProblem(Log.WARN, msg); } } - signingDetails = pkg.mSigningDetails; + signingDetails = parsedPackage.getSigningDetails(); } else { try { final VersionInfo versionInfo = request.versionInfos.get(installPackageName); final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo); final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo); final boolean compatMatch = verifySignatures(signatureCheckPs, - disabledPkgSetting, pkg.mSigningDetails, compareCompat, compareRecover); + disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat, + compareRecover); // 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 = pkg.mSigningDetails; + signingDetails = parsedPackage.getSigningDetails(); // if this is is a sharedUser, check to see if the new package is signed by a @@ -15448,10 +15278,10 @@ public class PackageManagerService extends IPackageManager.Stub // signing certificate than the existing one, and if so, copy over the new // details if (signatureCheckPs.sharedUser != null) { - if (pkg.mSigningDetails.hasAncestor( + if (parsedPackage.getSigningDetails().hasAncestor( signatureCheckPs.sharedUser.signatures.mSigningDetails)) { signatureCheckPs.sharedUser.signatures.mSigningDetails = - pkg.mSigningDetails; + parsedPackage.getSigningDetails(); } if (signatureCheckPs.sharedUser.signaturesChanged == null) { signatureCheckPs.sharedUser.signaturesChanged = Boolean.FALSE; @@ -15461,7 +15291,7 @@ public class PackageManagerService extends IPackageManager.Stub if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw new ReconcileFailure(e); } - signingDetails = pkg.mSigningDetails; + signingDetails = parsedPackage.getSigningDetails(); // If the system app is part of a shared user we allow that shared user to // change @@ -15476,7 +15306,7 @@ public class PackageManagerService extends IPackageManager.Stub signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures; if (signatureCheckPs.sharedUser.signaturesChanged != null && compareSignatures(sharedUserSignatures, - pkg.mSigningDetails.signatures) + parsedPackage.getSigningDetails().signatures) != PackageManager.SIGNATURE_MATCH) { if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) { // Mismatched signatures is an error and silently skipping system @@ -15496,18 +15326,19 @@ public class PackageManagerService extends IPackageManager.Stub // whichever package happened to be scanned later. throw new IllegalStateException( "Signature mismatch on system package " - + pkg.packageName + " for shared user " + + parsedPackage.getPackageName() + + " for shared user " + scanResult.pkgSetting.sharedUser); } } sharedUserSignaturesChanged = true; signatureCheckPs.sharedUser.signatures.mSigningDetails = - pkg.mSigningDetails; + parsedPackage.getSigningDetails(); signatureCheckPs.sharedUser.signaturesChanged = Boolean.TRUE; } // File a report about this. - String msg = "System package " + pkg.packageName + String msg = "System package " + parsedPackage.getPackageName() + " signature changed; retaining data."; reportSettingsProblem(Log.WARN, msg); } catch (IllegalArgumentException e) { @@ -15541,8 +15372,9 @@ public class PackageManagerService extends IPackageManager.Stub } try { result.get(installPackageName).collectedSharedLibraryInfos = - collectSharedLibraryInfos(scanResult.request.pkg, combinedPackages, - request.sharedLibrarySource, incomingSharedLibraries); + collectSharedLibraryInfos(scanResult.request.parsedPackage, + combinedPackages, request.sharedLibrarySource, + incomingSharedLibraries); } catch (PackageManagerException e) { throw new ReconcileFailure(e.error, e.getMessage()); @@ -15560,7 +15392,7 @@ public class PackageManagerService extends IPackageManager.Stub ScanResult scanResult, Map<String, LongSparseArray<SharedLibraryInfo>> existingSharedLibraries) { // Let's used the parsed package as scanResult.pkgSetting may be null - final PackageParser.Package pkg = scanResult.request.pkg; + final ParsedPackage parsedPackage = scanResult.request.parsedPackage; if (scanResult.staticSharedLibraryInfo == null && scanResult.dynamicSharedLibraryInfos == null) { return null; @@ -15571,12 +15403,12 @@ public class PackageManagerService extends IPackageManager.Stub return Collections.singletonList(scanResult.staticSharedLibraryInfo); } final boolean hasDynamicLibraries = - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 + (parsedPackage.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0 && scanResult.dynamicSharedLibraryInfos != null; if (!hasDynamicLibraries) { return null; } - final boolean isUpdatedSystemApp = pkg.isUpdatedSystemApp(); + final boolean isUpdatedSystemApp = parsedPackage.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 @@ -15585,9 +15417,9 @@ public class PackageManagerService extends IPackageManager.Stub : scanResult.request.disabledPkgSetting : null; if (isUpdatedSystemApp && (updatedSystemPs.pkg == null - || updatedSystemPs.pkg.libraryNames == null)) { - Slog.w(TAG, "Package " + pkg.packageName + " declares libraries that are not " - + "declared on the system image; skipping"); + || updatedSystemPs.pkg.getLibraryNames() == null)) { + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + + " declares libraries that are not declared on the system image; skipping"); return null; } final ArrayList<SharedLibraryInfo> infos = @@ -15605,16 +15437,17 @@ public class PackageManagerService extends IPackageManager.Stub // with it. Better to just have the restriction here, be // conservative, and create many fewer cases that can negatively // impact the user experience. - if (!updatedSystemPs.pkg.libraryNames.contains(name)) { - Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name + if (!updatedSystemPs.pkg.getLibraryNames().contains(name)) { + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + + " declares library " + name + " that is not declared on system image; skipping"); continue; } } if (sharedLibExists( name, SharedLibraryInfo.VERSION_UNDEFINED, existingSharedLibraries)) { - Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name - + " that already exists; skipping"); + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " declares library " + + name + " that already exists; skipping"); continue; } infos.add(info); @@ -15652,68 +15485,38 @@ public class PackageManagerService extends IPackageManager.Stub for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) { final ScanResult scanResult = reconciledPkg.scanResult; final ScanRequest scanRequest = scanResult.request; - final PackageParser.Package pkg = scanRequest.pkg; - final String packageName = pkg.packageName; + final ParsedPackage parsedPackage = scanRequest.parsedPackage; + final String packageName = parsedPackage.getPackageName(); final PackageInstalledInfo res = reconciledPkg.installResult; if (reconciledPkg.prepareResult.replace) { - PackageParser.Package oldPackage = mPackages.get(packageName); + AndroidPackage oldPackage = mPackages.get(packageName); // Set the update and install times - PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras; - setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime, - System.currentTimeMillis()); + PackageSetting deletedPkgSetting = getPackageSetting(oldPackage.getPackageName()); + reconciledPkg.pkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime; + reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis(); if (reconciledPkg.prepareResult.system) { // Remove existing system package removePackageLI(oldPackage, true); - if (!disableSystemPackageLPw(oldPackage, pkg)) { + if (!disableSystemPackageLPw(oldPackage)) { // We didn't need to disable the .apk as a current system package, // which means we are replacing another update that is already // installed. We need to make sure to delete the older one's .apk. res.removedInfo.args = createInstallArgsForExisting( - oldPackage.applicationInfo.getCodePath(), - oldPackage.applicationInfo.getResourcePath(), - getAppDexInstructionSets(oldPackage.applicationInfo)); + oldPackage.getAppInfoCodePath(), + oldPackage.getAppInfoResourcePath(), + getAppDexInstructionSets(oldPackage.getPrimaryCpuAbi(), + oldPackage.getSecondaryCpuAbi())); } else { res.removedInfo.args = null; } - - // Update the package dynamic state if succeeded - // Now that the install succeeded make sure we remove data - // directories for any child package the update removed. - final int deletedChildCount = (oldPackage.childPackages != null) - ? oldPackage.childPackages.size() : 0; - final int newChildCount = (pkg.childPackages != null) - ? pkg.childPackages.size() : 0; - for (int i = 0; i < deletedChildCount; i++) { - PackageParser.Package deletedChildPkg = oldPackage.childPackages.get(i); - boolean childPackageDeleted = true; - for (int j = 0; j < newChildCount; j++) { - PackageParser.Package newChildPkg = pkg.childPackages.get(j); - if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) { - childPackageDeleted = false; - break; - } - } - if (childPackageDeleted) { - PackageSetting ps1 = mSettings.getDisabledSystemPkgLPr( - deletedChildPkg.packageName); - if (ps1 != null && res.removedInfo.removedChildPackages != null) { - PackageRemovedInfo removedChildRes = res.removedInfo - .removedChildPackages.get(deletedChildPkg.packageName); - removePackageDataLIF(ps1, request.mAllUsers, removedChildRes, 0, - false); - removedChildRes.removedForAllUsers = mPackages.get(ps1.name) - == null; - } - } - } } else { try { // Settings will be written during the call to updateSettingsLI(). executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName, - true, request.mAllUsers, false, pkg); + true, request.mAllUsers, false, parsedPackage); } catch (SystemDeleteException e) { if (Build.IS_ENG) { throw new RuntimeException("Unexpected failure", e); @@ -15729,62 +15532,40 @@ public class PackageManagerService extends IPackageManager.Stub Slog.i(TAG, "upgrading pkg " + oldPackage + " is ASEC-hosted -> UNAVAILABLE"); } - final int[] uidArray = new int[]{oldPackage.applicationInfo.uid}; + final int[] uidArray = new int[]{oldPackage.getUid()}; final ArrayList<String> pkgList = new ArrayList<>(1); - pkgList.add(oldPackage.applicationInfo.packageName); + pkgList.add(oldPackage.getAppInfoPackageName()); sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null); } // Update the in-memory copy of the previous code paths. PackageSetting ps1 = mSettings.mPackages.get( - reconciledPkg.prepareResult.existingPackage.packageName); + reconciledPkg.prepareResult.existingPackage.getPackageName()); if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP) == 0) { if (ps1.mOldCodePaths == null) { ps1.mOldCodePaths = new ArraySet<>(); } - Collections.addAll(ps1.mOldCodePaths, oldPackage.baseCodePath); - if (oldPackage.splitCodePaths != null) { - Collections.addAll(ps1.mOldCodePaths, oldPackage.splitCodePaths); + Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseCodePath()); + if (oldPackage.getSplitCodePaths() != null) { + Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths()); } } else { ps1.mOldCodePaths = null; } - if (ps1.childPackageNames != null) { - for (int i = ps1.childPackageNames.size() - 1; i >= 0; --i) { - final String childPkgName = ps1.childPackageNames.get(i); - final PackageSetting childPs = mSettings.mPackages.get(childPkgName); - childPs.mOldCodePaths = ps1.mOldCodePaths; - } - } if (reconciledPkg.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) { - PackageSetting ps2 = mSettings.getPackageLPr(pkg.packageName); + PackageSetting ps2 = mSettings.getPackageLPr( + parsedPackage.getPackageName()); if (ps2 != null) { res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null; - if (res.removedInfo.removedChildPackages != null) { - final int childCount1 = res.removedInfo.removedChildPackages.size(); - // Iterate in reverse as we may modify the collection - for (int i = childCount1 - 1; i >= 0; i--) { - String childPackageName = - res.removedInfo.removedChildPackages.keyAt(i); - if (res.addedChildPackages.containsKey(childPackageName)) { - res.removedInfo.removedChildPackages.removeAt(i); - } else { - PackageRemovedInfo childInfo = res.removedInfo - .removedChildPackages.valueAt(i); - childInfo.removedForAllUsers = mPackages.get( - childInfo.removedPackage) == null; - } - } - } } } } } - commitReconciledScanResultLocked(reconciledPkg); + AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg); updateSettingsLI(pkg, reconciledPkg.installArgs, request.mAllUsers, res); final PackageSetting ps = mSettings.mPackages.get(packageName); @@ -15792,16 +15573,6 @@ public class PackageManagerService extends IPackageManager.Stub res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); ps.setUpdateAvailable(false /*updateAvailable*/); } - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName); - PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName); - if (childPs != null) { - childRes.newUsers = childPs.queryInstalledUsers( - mUserManager.getUserIds(), true); - } - } if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { updateSequenceNumberLP(ps, res.newUsers); updateInstantAppInstallerLocked(packageName); @@ -15862,33 +15633,31 @@ public class PackageManagerService extends IPackageManager.Stub request.installResult.installerPackageName = request.args.installSource.installerPackageName; - final String packageName = prepareResult.packageToScan.packageName; + final String packageName = prepareResult.packageToScan.getPackageName(); prepareResults.put(packageName, prepareResult); installResults.put(packageName, request.installResult); installArgs.put(packageName, request.args); try { - final List<ScanResult> scanResults = scanPackageTracedLI( + final ScanResult result = scanPackageTracedLI( prepareResult.packageToScan, prepareResult.parseFlags, prepareResult.scanFlags, System.currentTimeMillis(), request.args.user); - for (ScanResult result : scanResults) { - if (null != preparedScans.put(result.pkgSetting.pkg.packageName, result)) { - request.installResult.setError( - PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE, - "Duplicate package " + result.pkgSetting.pkg.packageName - + " in multi-package install request."); - return; - } - createdAppId.put(packageName, optimisticallyRegisterAppId(result)); - versionInfos.put(result.pkgSetting.pkg.packageName, - getSettingsVersionForPackage(result.pkgSetting.pkg)); - if (result.staticSharedLibraryInfo != null) { - final PackageSetting sharedLibLatestVersionSetting = - getSharedLibLatestVersionSetting(result); - if (sharedLibLatestVersionSetting != null) { - lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName, - sharedLibLatestVersionSetting); - } + if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) { + request.installResult.setError( + PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE, + "Duplicate package " + result.pkgSetting.pkg.getPackageName() + + " in multi-package install request."); + return; + } + createdAppId.put(packageName, optimisticallyRegisterAppId(result)); + versionInfos.put(result.pkgSetting.pkg.getPackageName(), + getSettingsVersionForPackage(result.pkgSetting.pkg)); + if (result.staticSharedLibraryInfo != null) { + final PackageSetting sharedLibLatestVersionSetting = + getSharedLibLatestVersionSetting(result); + if (sharedLibLatestVersionSetting != null) { + lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(), + sharedLibLatestVersionSetting); } } } catch (PackageManagerException e) { @@ -15931,23 +15700,20 @@ public class PackageManagerService extends IPackageManager.Stub } finally { if (!success) { for (ScanResult result : preparedScans.values()) { - if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) { + if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(), + false)) { cleanUpAppIdCreation(result); } } // TODO(patb): create a more descriptive reason than unknown in future release // mark all non-failure installs as UNKNOWN so we do not treat them as success for (InstallRequest request : requests) { + request.installResult.freezer.close(); if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) { request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN; } } } - for (PrepareResult result : prepareResults.values()) { - if (result.freezer != null) { - result.freezer.close(); - } - } Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } @@ -15961,18 +15727,18 @@ public class PackageManagerService extends IPackageManager.Stub for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) { final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags & PackageManagerService.SCAN_AS_INSTANT_APP) != 0); - final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg; - final String packageName = pkg.packageName; + final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg; + final String packageName = pkg.getPackageName(); final boolean onIncremental = mIncrementalManager != null - && isIncrementalPath(pkg.codePath); + && isIncrementalPath(pkg.getCodePath()); prepareAppDataAfterInstallLIF(pkg); if (reconciledPkg.prepareResult.clearCodeCache) { clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); } if (reconciledPkg.prepareResult.replace) { - mDexManager.notifyPackageUpdated(pkg.packageName, - pkg.baseCodePath, pkg.splitCodePaths); + mDexManager.notifyPackageUpdated(pkg.getPackageName(), + pkg.getBaseCodePath(), pkg.getSplitCodePaths()); } // Prepare the application profiles for the new code paths. @@ -15986,7 +15752,7 @@ public class PackageManagerService extends IPackageManager.Stub // Check whether we need to dexopt the app. // // NOTE: it is IMPORTANT to call dexopt: - // - after doRename which will sync the package data from PackageParser.Package and + // - after doRename which will sync the package data from AndroidPackage and // its corresponding ApplicationInfo. // - after installNewPackageLIF or replacePackageLIF which will update result with the // uid of the application (pkg.applicationInfo.uid). @@ -16006,7 +15772,7 @@ public class PackageManagerService extends IPackageManager.Stub final boolean performDexopt = (!instantApp || Global.getInt(mContext.getContentResolver(), Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) - && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) + && ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) == 0) && (!onIncremental); if (performDexopt) { @@ -16051,20 +15817,17 @@ public class PackageManagerService extends IPackageManager.Stub public final int scanFlags; public final int parseFlags; @Nullable /* The original Package if it is being replaced, otherwise {@code null} */ - public final PackageParser.Package existingPackage; - public final PackageParser.Package packageToScan; + public final AndroidPackage existingPackage; + public final ParsedPackage packageToScan; public final boolean clearCodeCache; public final boolean system; - public final PackageFreezer freezer; public final PackageSetting originalPs; public final PackageSetting disabledPs; - public final PackageSetting[] childPackageSettings; private PrepareResult(boolean replace, int scanFlags, - int parseFlags, PackageParser.Package existingPackage, - PackageParser.Package packageToScan, boolean clearCodeCache, boolean system, - PackageFreezer freezer, PackageSetting originalPs, - PackageSetting disabledPs, PackageSetting[] childPackageSettings) { + int parseFlags, AndroidPackage existingPackage, + ParsedPackage packageToScan, boolean clearCodeCache, boolean system, + PackageSetting originalPs, PackageSetting disabledPs) { this.replace = replace; this.scanFlags = scanFlags; this.parseFlags = parseFlags; @@ -16072,10 +15835,8 @@ public class PackageManagerService extends IPackageManager.Stub this.packageToScan = packageToScan; this.clearCodeCache = clearCodeCache; this.system = system; - this.freezer = freezer; this.originalPs = originalPs; this.disabledPs = disabledPs; - this.childPackageSettings = childPackageSettings; } } @@ -16154,10 +15915,10 @@ public class PackageManagerService extends IPackageManager.Stub pp.setCallback(mPackageParserCallback); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); - final PackageParser.Package pkg; + ParsedPackage parsedPackage; try { - pkg = pp.parsePackage(tmpPackageFile, parseFlags); - DexMetadataHelper.validatePackageDexMetadata(pkg); + parsedPackage = pp.parseParsedPackage(tmpPackageFile, parseFlags, false); + DexMetadataHelper.validatePackageDexMetadata(parsedPackage); } catch (PackageParserException e) { throw new PrepareFailure("Failed parse during installPackageLI", e); } finally { @@ -16166,23 +15927,23 @@ public class PackageManagerService extends IPackageManager.Stub // Instant apps have several additional install-time checks. if (instantApp) { - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) { - Slog.w(TAG, - "Instant app package " + pkg.packageName + " does not target at least O"); + if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) { + Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() + + " does not target at least O"); throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID, "Instant app package must target at least O"); } - if (pkg.mSharedUserId != null) { - Slog.w(TAG, "Instant app package " + pkg.packageName + if (parsedPackage.getSharedUserId() != null) { + Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() + " may not declare sharedUserId."); throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID, "Instant app package may not declare a sharedUserId"); } } - if (pkg.applicationInfo.isStaticSharedLibrary()) { + if (parsedPackage.isStaticSharedLibrary()) { // Static shared libraries have synthetic package names - renameStaticSharedLibraryPackage(pkg); + renameStaticSharedLibraryPackage(parsedPackage); // No static shared libs on external storage if (onExternal) { @@ -16192,43 +15953,16 @@ public class PackageManagerService extends IPackageManager.Stub } } - // If we are installing a clustered package add results for the children - if (pkg.childPackages != null) { - synchronized (mLock) { - final int childCount = pkg.childPackages.size(); - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - PackageInstalledInfo childRes = new PackageInstalledInfo(); - childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED); - childRes.pkg = childPkg; - childRes.name = childPkg.packageName; - PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName); - if (childPs != null) { - childRes.origUsers = childPs.queryInstalledUsers( - mUserManager.getUserIds(), true); - } - if ((mPackages.containsKey(childPkg.packageName))) { - childRes.removedInfo = new PackageRemovedInfo(this); - childRes.removedInfo.removedPackage = childPkg.packageName; - childRes.removedInfo.installerPackageName = - childPs.installSource.installerPackageName; - } - if (res.addedChildPackages == null) { - res.addedChildPackages = new ArrayMap<>(); - } - res.addedChildPackages.put(childPkg.packageName, childRes); - } - } - } - // If package doesn't declare API override, mark that we have an install // time CPU ABI override. - if (TextUtils.isEmpty(pkg.cpuAbiOverride)) { - pkg.cpuAbiOverride = args.abiOverride; + // TODO(b/135203078): Isn't this always true because cpuAbiOverride isn't assigned during + // parsing? + if (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())) { + parsedPackage.setCpuAbiOverride(args.abiOverride); } - String pkgName = res.name = pkg.packageName; - if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) { + String pkgName = res.name = parsedPackage.getPackageName(); + if ((parsedPackage.getFlags() & ApplicationInfo.FLAG_TEST_ONLY) != 0) { if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) { throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI"); } @@ -16237,18 +15971,18 @@ public class PackageManagerService extends IPackageManager.Stub try { // either use what we've been given or parse directly from the APK if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) { - pkg.setSigningDetails(args.signingDetails); + parsedPackage.setSigningDetails(args.signingDetails); } else { // TODO(b/136132412): skip for Incremental installation - PackageParser.collectCertificates(pkg, false /* skipVerify */); + ApkParseUtils.collectCertificates(parsedPackage, false /* skipVerify */); } } catch (PackageParserException e) { throw new PrepareFailure("Failed collect during installPackageLI", e); } - if (instantApp && pkg.mSigningDetails.signatureSchemeVersion + if (instantApp && parsedPackage.getSigningDetails().signatureSchemeVersion < SignatureSchemeVersion.SIGNING_BLOCK_V2) { - Slog.w(TAG, "Instant app package " + pkg.packageName + Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() + " is not signed with at least APK Signature Scheme v2"); throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID, "Instant app package must be signed with APK Signature Scheme v2 or greater"); @@ -16262,15 +15996,15 @@ public class PackageManagerService extends IPackageManager.Stub // Check if installing already existing package if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { String oldName = mSettings.getRenamedPackageLPr(pkgName); - if (pkg.mOriginalPackages != null - && pkg.mOriginalPackages.contains(oldName) + if (parsedPackage.getOriginalPackages() != null + && parsedPackage.getOriginalPackages().contains(oldName) && mPackages.containsKey(oldName)) { // This package is derived from an original package, // and this device has been updating from that original // name. We must continue using the original name, so // rename the new package here. - pkg.setPackageName(oldName); - pkgName = pkg.packageName; + parsedPackage.setPackageName(oldName); + pkgName = parsedPackage.getPackageName(); replace = true; if (DEBUG_INSTALL) { Slog.d(TAG, "Replacing existing renamed package: oldName=" @@ -16283,43 +16017,27 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName); } - // Child packages are installed through the parent package - if (pkg.parentPackage != null) { - throw new PrepareFailure( - PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, - "Package " + pkg.packageName + " is child of package " - + pkg.parentPackage.parentPackage + ". Child packages " - + "can be updated only through the parent package."); - } - if (replace) { // Prevent apps opting out from runtime permissions - PackageParser.Package oldPackage = mPackages.get(pkgName); - final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion; - final int newTargetSdk = pkg.applicationInfo.targetSdkVersion; + AndroidPackage oldPackage = mPackages.get(pkgName); + final int oldTargetSdk = oldPackage.getTargetSdkVersion(); + final int newTargetSdk = parsedPackage.getTargetSdkVersion(); if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1 && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) { throw new PrepareFailure( PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE, - "Package " + pkg.packageName + " new target SDK " + newTargetSdk + "Package " + parsedPackage.getPackageName() + + " new target SDK " + newTargetSdk + " doesn't support runtime permissions but the old" + " target SDK " + oldTargetSdk + " does."); } // Prevent persistent apps from being updated - if (((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0) + if (((oldPackage.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0) && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) { throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK, - "Package " + oldPackage.packageName + " is a persistent app. " + "Package " + oldPackage.getPackageName() + " is a persistent app. " + "Persistent apps are not updateable."); } - // Prevent installing of child packages - if (oldPackage.parentPackage != null) { - throw new PrepareFailure( - PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, - "Package " + pkg.packageName + " is child of package " - + oldPackage.parentPackage + ". Child packages " - + "can be updated only through the parent package."); - } } } @@ -16332,8 +16050,8 @@ public class PackageManagerService extends IPackageManager.Stub // of the same package, therefore we need to compare signatures against // the package setting for the latest library version. PackageSetting signatureCheckPs = ps; - if (pkg.applicationInfo.isStaticSharedLibrary()) { - SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(pkg); + if (parsedPackage.isStaticSharedLibrary()) { + SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(parsedPackage); if (libraryInfo != null) { signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName()); } @@ -16344,23 +16062,23 @@ public class PackageManagerService extends IPackageManager.Stub // bail early here before tripping over redefined permissions. final KeySetManagerService ksms = mSettings.mKeySetManagerService; if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) { - if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) { + if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) { throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " - + pkg.packageName + " upgrade keys do not match the " + + parsedPackage.getPackageName() + " upgrade keys do not match the " + "previously installed version"); } } else { try { - final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg); - final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg); + final boolean compareCompat = isCompatSignatureUpdateNeeded(parsedPackage); + final boolean compareRecover = isRecoverSignatureUpdateNeeded( + parsedPackage); // We don't care about disabledPkgSetting on install for now. - final boolean compatMatch = verifySignatures( - signatureCheckPs, null, pkg.mSigningDetails, compareCompat, - compareRecover); + final boolean compatMatch = verifySignatures(signatureCheckPs, null, + parsedPackage.getSigningDetails(), compareCompat, compareRecover); // The new KeySets will be re-added later in the scanning process. if (compatMatch) { synchronized (mLock) { - ksms.removeAppKeySetDataLPw(pkg.packageName); + ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName()); } } } catch (PackageManagerException e) { @@ -16368,27 +16086,25 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (ps.pkg != null && ps.pkg.applicationInfo != null) { - systemApp = (ps.pkg.applicationInfo.flags & - ApplicationInfo.FLAG_SYSTEM) != 0; + if (ps.pkg != null) { + systemApp = (ps.pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0; } res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); } - int N = pkg.permissions.size(); + int N = ArrayUtils.size(parsedPackage.getPermissions()); for (int i = N - 1; i >= 0; i--) { - final PackageParser.Permission perm = pkg.permissions.get(i); - final BasePermission bp = - (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name); + final ParsedPermission perm = parsedPackage.getPermissions().get(i); + final BasePermission bp = mPermissionManager.getPermissionTEMP(perm.getName()); // Don't allow anyone but the system to define ephemeral permissions. - if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0 + if ((perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0 && !systemApp) { - Slog.w(TAG, "Non-System package " + pkg.packageName + Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName() + " attempting to delcare ephemeral permission " - + perm.info.name + "; Removing ephemeral."); - perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT; + + perm.getName() + "; Removing ephemeral."); + perm.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT; } // Check whether the newly-scanned package wants to define an already-defined perm @@ -16400,26 +16116,27 @@ public class PackageManagerService extends IPackageManager.Stub final String sourcePackageName = bp.getSourcePackageName(); final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting(); final KeySetManagerService ksms = mSettings.mKeySetManagerService; - if (sourcePackageName.equals(pkg.packageName) + if (sourcePackageName.equals(parsedPackage.getPackageName()) && (ksms.shouldCheckUpgradeKeySetLocked( sourcePackageSetting, scanFlags))) { - sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg); + sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage); } else { // in the event of signing certificate rotation, we need to see if the // package's certificate has rotated from the current one, or if it is an // older certificate with which the current is ok with sharing permissions if (sourcePackageSetting.signatures.mSigningDetails.checkCapability( - pkg.mSigningDetails, + parsedPackage.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.PERMISSION)) { sigsOk = true; - } else if (pkg.mSigningDetails.checkCapability( + } else if (parsedPackage.getSigningDetails().checkCapability( sourcePackageSetting.signatures.mSigningDetails, PackageParser.SigningDetails.CertCapabilities.PERMISSION)) { // the scanned package checks out, has signing certificate rotation // history, and is newer; bring it over - sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails; + sourcePackageSetting.signatures.mSigningDetails = + parsedPackage.getSigningDetails(); sigsOk = true; } else { sigsOk = false; @@ -16431,30 +16148,31 @@ public class PackageManagerService extends IPackageManager.Stub // redefinitions. if (!sourcePackageName.equals("android")) { throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package " - + pkg.packageName + + parsedPackage.getPackageName() + " attempting to redeclare permission " - + perm.info.name + " already owned by " + + perm.getName() + " already owned by " + sourcePackageName) - .conflictsWithExistingPermission(perm.info.name, + .conflictsWithExistingPermission(perm.getName(), sourcePackageName); } else { - Slog.w(TAG, "Package " + pkg.packageName + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " attempting to redeclare system permission " - + perm.info.name + "; ignoring new declaration"); - pkg.permissions.remove(i); + + perm.getName() + "; ignoring new declaration"); + parsedPackage.removePermission(i); } - } else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) { + } else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) { // Prevent apps to change protection level to dangerous from any other // type as this would allow a privilege escalation where an app adds a // normal/signature permission in other app's group and later redefines // it as dangerous leading to the group auto-grant. - if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) + if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) == PermissionInfo.PROTECTION_DANGEROUS) { if (bp != null && !bp.isRuntime()) { - Slog.w(TAG, "Package " + pkg.packageName + " trying to change a " - + "non-runtime permission " + perm.info.name + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + + " trying to change a non-runtime permission " + + perm.getName() + " to runtime; keeping old protection level"); - perm.info.protectionLevel = bp.getProtectionLevel(); + perm.protectionLevel = bp.getProtectionLevel(); } } } @@ -16488,8 +16206,8 @@ public class PackageManagerService extends IPackageManager.Stub // We moved the entire application as-is, so bring over the // previously derived ABI information. - pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString; - pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString; + parsedPackage.setPrimaryCpuAbi(ps.primaryCpuAbiString) + .setSecondaryCpuAbi(ps.secondaryCpuAbiString); } } else { @@ -16497,14 +16215,14 @@ public class PackageManagerService extends IPackageManager.Stub scanFlags |= SCAN_NO_DEX; try { - String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ? - args.abiOverride : pkg.cpuAbiOverride); - final boolean extractNativeLibs = !pkg.isLibrary(); + String abiOverride = (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride()) + ? args.abiOverride : parsedPackage.getCpuAbiOverride()); + final boolean extractNativeLibs = !parsedPackage.isLibrary(); final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi = mInjector.getAbiHelper().derivePackageAbi( - pkg, abiOverride, extractNativeLibs); - derivedAbi.first.applyTo(pkg); - derivedAbi.second.applyTo(pkg); + parsedPackage, abiOverride, extractNativeLibs); + derivedAbi.first.applyTo(parsedPackage); + derivedAbi.second.applyTo(parsedPackage); } catch (PackageManagerException pme) { Slog.e(TAG, "Error deriving application ABI", pme); throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, @@ -16512,19 +16230,19 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (!args.doRename(res.returnCode, pkg)) { + if (!args.doRename(res.returnCode, parsedPackage)) { throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename"); } try { - setUpFsVerityIfPossible(pkg); + setUpFsVerityIfPossible(parsedPackage); } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) { throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, "Failed to set up verity: " + e); } if (!instantApp) { - startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg); + startIntentFilterVerifications(args.user.getIdentifier(), replace, parsedPackage); } else { if (DEBUG_DOMAIN_VERIFICATION) { Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName); @@ -16534,7 +16252,7 @@ public class PackageManagerService extends IPackageManager.Stub freezePackageForInstall(pkgName, installFlags, "installPackageLI"); boolean shouldCloseFreezerBeforeReturn = true; try { - final PackageParser.Package existingPackage; + final AndroidPackage existingPackage; String renamedPackage = null; boolean sysPkg = false; int targetScanFlags = scanFlags; @@ -16543,14 +16261,15 @@ public class PackageManagerService extends IPackageManager.Stub final PackageSetting disabledPs; final PackageSetting[] childPackages; if (replace) { - if (pkg.applicationInfo.isStaticSharedLibrary()) { + if (parsedPackage.isStaticSharedLibrary()) { // Static libs have a synthetic package name containing the version // and cannot be updated as an update would get a new package name, // unless this is the exact same version code which is useful for // development. - PackageParser.Package existingPkg = mPackages.get(pkg.packageName); + AndroidPackage existingPkg = mPackages.get(parsedPackage.getPackageName()); if (existingPkg != null - && existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) { + && existingPkg.getLongVersionCode() + != parsedPackage.getLongVersionCode()) { throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring " + "static-shared libs cannot be updated"); @@ -16559,8 +16278,8 @@ public class PackageManagerService extends IPackageManager.Stub final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; - final PackageParser.Package oldPackage; - final String pkgName11 = pkg.packageName; + final AndroidPackage oldPackage; + final String pkgName11 = parsedPackage.getPackageName(); final int[] allUsers; final int[] installedUsers; @@ -16568,8 +16287,9 @@ public class PackageManagerService extends IPackageManager.Stub oldPackage = mPackages.get(pkgName11); existingPackage = oldPackage; if (DEBUG_INSTALL) { + // TODO(b/135203078): PackageImpl.toString() Slog.d(TAG, - "replacePackageLI: new=" + pkg + ", old=" + oldPackage); + "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage); } ps = mSettings.mPackages.get(pkgName11); @@ -16578,17 +16298,18 @@ public class PackageManagerService extends IPackageManager.Stub // verify signatures are valid final KeySetManagerService ksms = mSettings.mKeySetManagerService; if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) { - if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) { + if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) { throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "New package not signed by keys specified by upgrade-keysets: " + pkgName11); } } else { // default to original signature matching - if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails, + if (!parsedPackage.getSigningDetails().checkCapability( + oldPackage.getSigningDetails(), SigningDetails.CertCapabilities.INSTALLED_DATA) - && !oldPackage.mSigningDetails.checkCapability( - pkg.mSigningDetails, + && !oldPackage.getSigningDetails().checkCapability( + parsedPackage.getSigningDetails(), SigningDetails.CertCapabilities.ROLLBACK)) { throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "New package has a different signature: " + pkgName11); @@ -16596,13 +16317,13 @@ public class PackageManagerService extends IPackageManager.Stub } // don't allow a system upgrade unless the upgrade hash matches - if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) { + if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) { final byte[] digestBytes; try { final MessageDigest digest = MessageDigest.getInstance("SHA-512"); - updateDigest(digest, new File(pkg.baseCodePath)); - if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { - for (String path : pkg.splitCodePaths) { + updateDigest(digest, new File(parsedPackage.getBaseCodePath())); + if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) { + for (String path : parsedPackage.getSplitCodePaths()) { updateDigest(digest, new File(path)); } } @@ -16611,21 +16332,25 @@ public class PackageManagerService extends IPackageManager.Stub throw new PrepareFailure(INSTALL_FAILED_INVALID_APK, "Could not compute hash: " + pkgName11); } - if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) { + if (!Arrays.equals(oldPackage.getRestrictUpdateHash(), digestBytes)) { throw new PrepareFailure(INSTALL_FAILED_INVALID_APK, "New package fails restrict-update check: " + pkgName11); } // retain upgrade restriction - pkg.restrictUpdateHash = oldPackage.restrictUpdateHash; + parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash()); } // Check for shared user id changes - String invalidPackageName = - getParentOrChildPackageChangedSharedUser(oldPackage, pkg); + String invalidPackageName = null; + if (!Objects.equals(oldPackage.getSharedUserId(), + parsedPackage.getSharedUserId())) { + invalidPackageName = parsedPackage.getPackageName(); + } + if (invalidPackageName != null) { throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE, "Package " + invalidPackageName + " tried to change user " - + oldPackage.mSharedUserId); + + oldPackage.getSharedUserId()); } // In case of rollback, remember per-user/profile install state @@ -16658,10 +16383,10 @@ public class PackageManagerService extends IPackageManager.Stub // Update what is removed res.removedInfo = new PackageRemovedInfo(this); - res.removedInfo.uid = oldPackage.applicationInfo.uid; - res.removedInfo.removedPackage = oldPackage.packageName; + res.removedInfo.uid = oldPackage.getUid(); + res.removedInfo.removedPackage = oldPackage.getPackageName(); res.removedInfo.installerPackageName = ps.installSource.installerPackageName; - res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null; + res.removedInfo.isStaticSharedLib = parsedPackage.getStaticSharedLibName() != null; res.removedInfo.isUpdate = true; res.removedInfo.origUsers = installedUsers; res.removedInfo.installReasons = new SparseArray<>(installedUsers.length); @@ -16670,53 +16395,6 @@ public class PackageManagerService extends IPackageManager.Stub res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId)); } - childPackages = mSettings.getChildSettingsLPr(ps); - if (childPackages != null) { - for (PackageSetting childPs : childPackages) { - boolean childPackageUpdated = false; - PackageParser.Package childPkg = (childPs == null) ? null : childPs.pkg; - if (res.addedChildPackages != null) { - PackageInstalledInfo childRes = res.addedChildPackages.get( - childPkg.packageName); - if (childRes != null) { - childRes.removedInfo.uid = childPkg.applicationInfo.uid; - childRes.removedInfo.removedPackage = childPkg.packageName; - if (childPs != null) { - childRes.removedInfo.installerPackageName = - childPs.installSource.installerPackageName; - } - childRes.removedInfo.isUpdate = true; - childRes.removedInfo.installReasons = - res.removedInfo.installReasons; - childPackageUpdated = true; - } - } - if (!childPackageUpdated) { - PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this); - childRemovedRes.removedPackage = childPkg.packageName; - if (childPs != null) { - childRemovedRes.installerPackageName = - childPs.installSource.installerPackageName; - } - childRemovedRes.isUpdate = false; - childRemovedRes.dataRemoved = true; - synchronized (mLock) { - if (childPs != null) { - childRemovedRes.origUsers = childPs.queryInstalledUsers( - allUsers, - true); - } - } - if (res.removedInfo.removedChildPackages == null) { - res.removedInfo.removedChildPackages = new ArrayMap<>(); - } - res.removedInfo.removedChildPackages.put(childPkg.packageName, - childRemovedRes); - } - } - } - - sysPkg = (isSystemApp(oldPackage)); if (sysPkg) { // Set the system/privileged/oem/vendor/product flags as needed @@ -16735,41 +16413,30 @@ public class PackageManagerService extends IPackageManager.Stub | (odm ? SCAN_AS_ODM : 0); if (DEBUG_INSTALL) { - Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg + Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage + ", old=" + oldPackage); } res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); - pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, - ApplicationInfo.FLAG_UPDATED_SYSTEM_APP); + parsedPackage.setUpdatedSystemApp(true); targetParseFlags = systemParseFlags; targetScanFlags = systemScanFlags; } else { // non system replace replace = true; if (DEBUG_INSTALL) { Slog.d(TAG, - "replaceNonSystemPackageLI: new=" + pkg + ", old=" + "replaceNonSystemPackageLI: new=" + parsedPackage + ", old=" + oldPackage); } - - String pkgName1 = oldPackage.packageName; - boolean deletedPkg = true; - boolean addedPkg = false; - boolean updatedSettings = false; - - final long origUpdateTime = (pkg.mExtras != null) - ? ((PackageSetting) pkg.mExtras).lastUpdateTime : 0; - } } else { // new package install ps = null; - childPackages = null; disabledPs = null; replace = false; existingPackage = null; // Remember this for later, in case we need to rollback this install - String pkgName1 = pkg.packageName; + String pkgName1 = parsedPackage.getPackageName(); - if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg); + if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + parsedPackage); // TODO(patb): MOVE TO RECONCILE synchronized (mLock) { @@ -16796,9 +16463,10 @@ public class PackageManagerService extends IPackageManager.Stub shouldCloseFreezerBeforeReturn = false; return new PrepareResult(replace, targetScanFlags, targetParseFlags, - existingPackage, pkg, replace /* clearCodeCache */, sysPkg, freezer, - ps, disabledPs, childPackages); + existingPackage, parsedPackage, replace /* clearCodeCache */, sysPkg, + ps, disabledPs); } finally { + res.freezer = freezer; if (shouldCloseFreezerBeforeReturn) { freezer.close(); } @@ -16812,7 +16480,7 @@ public class PackageManagerService extends IPackageManager.Stub * <p>When the feature flag is set to legacy mode, only APK is supported (with some experimental * kernel patches). In normal mode, all file format can be supported. */ - private void setUpFsVerityIfPossible(PackageParser.Package pkg) throws InstallerException, + private void setUpFsVerityIfPossible(AndroidPackage pkg) throws InstallerException, PrepareFailure, IOException, DigestException, NoSuchAlgorithmException { final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled(); final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled(); @@ -16824,11 +16492,11 @@ public class PackageManagerService extends IPackageManager.Stub ArrayMap<String, String> fsverityCandidates = new ArrayMap<>(); if (legacyMode) { synchronized (mLock) { - final PackageSetting ps = mSettings.mPackages.get(pkg.packageName); + final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName()); if (ps != null && ps.isPrivileged()) { - fsverityCandidates.put(pkg.baseCodePath, null); - if (pkg.splitCodePaths != null) { - for (String splitPath : pkg.splitCodePaths) { + fsverityCandidates.put(pkg.getBaseCodePath(), null); + if (pkg.getSplitCodePaths() != null) { + for (String splitPath : pkg.getSplitCodePaths()) { fsverityCandidates.put(splitPath, null); } } @@ -16837,16 +16505,17 @@ public class PackageManagerService extends IPackageManager.Stub } else { // NB: These files will become only accessible if the signing key is loaded in kernel's // .fs-verity keyring. - fsverityCandidates.put(pkg.baseCodePath, - VerityUtils.getFsveritySignatureFilePath(pkg.baseCodePath)); + fsverityCandidates.put(pkg.getBaseCodePath(), + VerityUtils.getFsveritySignatureFilePath(pkg.getBaseCodePath())); - final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(pkg.baseCodePath); + final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk( + pkg.getBaseCodePath()); if (new File(dmPath).exists()) { fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath)); } - if (pkg.splitCodePaths != null) { - for (String path : pkg.splitCodePaths) { + if (pkg.getSplitCodePaths() != null) { + for (String path : pkg.getSplitCodePaths()) { fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path)); final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path); @@ -16900,8 +16569,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void startIntentFilterVerifications(int userId, boolean replacing, - PackageParser.Package pkg) { + private void startIntentFilterVerifications(int userId, boolean replacing, AndroidPackage pkg) { if (mIntentFilterVerifierComponent == null) { Slog.w(TAG, "No IntentFilter verification will not be done as " + "there is no IntentFilterVerifier available!"); @@ -16914,29 +16582,29 @@ public class PackageManagerService extends IPackageManager.Stub (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId); Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS); - msg.obj = new IFVerificationParams(pkg, replacing, userId, verifierUid); + msg.obj = new IFVerificationParams( + pkg.getPackageName(), + hasDomainURLs(pkg), + pkg.getActivities(), + replacing, + userId, + verifierUid + ); mHandler.sendMessage(msg); - - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS); - msg.obj = new IFVerificationParams(childPkg, replacing, userId, verifierUid); - mHandler.sendMessage(msg); - } } private void verifyIntentFiltersIfNeeded(int userId, int verifierUid, boolean replacing, - PackageParser.Package pkg) { - int size = pkg.activities.size(); + String packageName, + boolean hasDomainUrls, + List<ParsedActivity> activities) { + int size = activities.size(); if (size == 0) { if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "No activity, so no need to verify any IntentFilter!"); return; } - final boolean hasDomainURLs = hasDomainURLs(pkg); - if (!hasDomainURLs) { + if (!hasDomainUrls) { if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "No domain URLs, so no need to verify any IntentFilter!"); return; @@ -16947,7 +16615,6 @@ public class PackageManagerService extends IPackageManager.Stub + " Activities needs verification ..."); int count = 0; - final String packageName = pkg.packageName; synchronized (mLock) { // If this is a new install and we see that we've already run verification for this @@ -16966,8 +16633,8 @@ public class PackageManagerService extends IPackageManager.Stub // If any filters need to be verified, then all need to be. boolean needToVerify = false; - for (PackageParser.Activity a : pkg.activities) { - for (ActivityIntentInfo filter : a.intents) { + for (ParsedActivity a : activities) { + for (ParsedActivityIntentInfo filter : a.intents) { if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) { if (DEBUG_DOMAIN_VERIFICATION) { Slog.d(TAG, @@ -16981,8 +16648,8 @@ public class PackageManagerService extends IPackageManager.Stub if (needToVerify) { final int verificationId = mIntentFilterVerificationToken++; - for (PackageParser.Activity a : pkg.activities) { - for (ActivityIntentInfo filter : a.intents) { + for (ParsedActivity a : activities) { + for (ParsedActivityIntentInfo filter : a.intents) { if (filter.handlesWebUris(true) && needsNetworkVerificationLPr(filter)) { if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Verification needed for IntentFilter:" + filter.toString()); @@ -17008,9 +16675,8 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private boolean needsNetworkVerificationLPr(ActivityIntentInfo filter) { - final ComponentName cn = filter.activity.getComponentName(); - final String packageName = cn.getPackageName(); + private boolean needsNetworkVerificationLPr(ParsedActivityIntentInfo filter) { + final String packageName = filter.getPackageName(); IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr( packageName); @@ -17030,45 +16696,45 @@ public class PackageManagerService extends IPackageManager.Stub } } - private static boolean isExternal(PackageParser.Package pkg) { - return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; + private static boolean isExternal(AndroidPackage pkg) { + return (pkg.getFlags() & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; } private static boolean isExternal(PackageSetting ps) { return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; } - static boolean isSystemApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + static boolean isSystemApp(AndroidPackage pkg) { + return (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0; } - private static boolean isPrivilegedApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; + private static boolean isPrivilegedApp(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; } - private static boolean isOemApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0; + private static boolean isOemApp(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_OEM) != 0; } - private static boolean isVendorApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; + private static boolean isVendorApp(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; } - private static boolean isProductApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; + private static boolean isProductApp(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; } - private static boolean isSystemExtApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags + private static boolean isSystemExtApp(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0; } - private static boolean isOdmApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0; + private static boolean isOdmApp(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_ODM) != 0; } - private static boolean hasDomainURLs(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0; + private static boolean hasDomainURLs(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0; } private static boolean isSystemApp(PackageSetting ps) { @@ -17079,12 +16745,12 @@ public class PackageManagerService extends IPackageManager.Stub return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } - private VersionInfo getSettingsVersionForPackage(PackageParser.Package pkg) { + private VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) { if (isExternal(pkg)) { - if (TextUtils.isEmpty(pkg.volumeUuid)) { + if (TextUtils.isEmpty(pkg.getVolumeUuid())) { return mSettings.getExternalVersion(); } else { - return mSettings.findOrCreateVersion(pkg.volumeUuid); + return mSettings.findOrCreateVersion(pkg.getVolumeUuid()); } } else { return mSettings.getInternalVersion(); @@ -17092,6 +16758,7 @@ public class PackageManagerService extends IPackageManager.Stub } private void deleteTempPackageFiles() { + // TODO: Is this used? final FilenameFilter filter = (dir, name) -> name.startsWith("vmdl") && name.endsWith(".tmp"); } @@ -17225,11 +16892,11 @@ public class PackageManagerService extends IPackageManager.Stub }); } - private String resolveExternalPackageNameLPr(PackageParser.Package pkg) { - if (pkg.staticSharedLibName != null) { - return pkg.manifestPackageName; + private String resolveExternalPackageNameLPr(AndroidPackage pkg) { + if (pkg.getStaticSharedLibName() != null) { + return pkg.getManifestPackageName(); } - return pkg.packageName; + return pkg.getPackageName(); } @GuardedBy("mLock") @@ -17436,7 +17103,7 @@ public class PackageManagerService extends IPackageManager.Stub final PackageSetting uninstalledPs; final PackageSetting disabledSystemPs; - final PackageParser.Package pkg; + final AndroidPackage pkg; // for the uninstall-updates case and restricted profiles, remember the per- // user handle installed state @@ -17468,9 +17135,9 @@ public class PackageManagerService extends IPackageManager.Stub allUsers = mUserManager.getUserIds(); - if (pkg != null && pkg.staticSharedLibName != null) { - SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(pkg.staticSharedLibName, - pkg.staticSharedLibVersion); + if (pkg != null && pkg.getStaticSharedLibName() != null) { + SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr( + pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion()); if (libraryInfo != null) { for (int currUserId : allUsers) { if (removeUser != UserHandle.USER_ALL && removeUser != currUserId) { @@ -17479,7 +17146,7 @@ public class PackageManagerService extends IPackageManager.Stub List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr( libraryInfo, MATCH_KNOWN_PACKAGES, currUserId); if (!ArrayUtils.isEmpty(libClientPackages)) { - Slog.w(TAG, "Not removing package " + pkg.manifestPackageName + Slog.w(TAG, "Not removing package " + pkg.getManifestPackageName() + " hosting lib " + libraryInfo.getName() + " version " + libraryInfo.getLongVersion() + " used by " + libClientPackages + " for user " + currUserId); @@ -17534,13 +17201,13 @@ public class PackageManagerService extends IPackageManager.Stub if (info.args != null) { info.args.doPostDeleteLI(true); } - final PackageParser.Package stubPkg = + final AndroidPackage stubPkg = (disabledSystemPs == null) ? null : disabledSystemPs.pkg; - if (stubPkg != null && stubPkg.isStub) { + if (stubPkg != null && stubPkg.isStub()) { synchronized (mLock) { // restore the enabled state of the stub; the state is overwritten when // the stub is uninstalled - final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName); + final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.getPackageName()); if (stubPs != null) { stubPs.setEnabled(origEnabledState, userId, "android"); } @@ -17549,7 +17216,7 @@ public class PackageManagerService extends IPackageManager.Stub || origEnabledState == COMPONENT_ENABLED_STATE_ENABLED) { if (DEBUG_COMPRESSION) { Slog.i(TAG, "Enabling system stub after removal; pkg: " - + stubPkg.packageName); + + stubPkg.getPackageName()); } enableCompressedPackage(stubPkg); } @@ -17577,7 +17244,6 @@ public class PackageManagerService extends IPackageManager.Stub boolean isStaticSharedLib; // Clean up resources deleted packages. InstallArgs args = null; - ArrayMap<String, PackageRemovedInfo> removedChildPackages; ArrayMap<String, PackageInstalledInfo> appearedChildPackages; PackageRemovedInfo(PackageSender packageSender) { @@ -17586,24 +17252,11 @@ public class PackageManagerService extends IPackageManager.Stub void sendPackageRemovedBroadcasts(boolean killApp) { sendPackageRemovedBroadcastInternal(killApp); - final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageRemovedInfo childInfo = removedChildPackages.valueAt(i); - childInfo.sendPackageRemovedBroadcastInternal(killApp); - } } void sendSystemPackageUpdatedBroadcasts() { if (isRemovedPackageSystemUpdate) { sendSystemPackageUpdatedBroadcastsInternal(); - final int childCount = (removedChildPackages != null) - ? removedChildPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageRemovedInfo childInfo = removedChildPackages.valueAt(i); - if (childInfo.isRemovedPackageSystemUpdate) { - childInfo.sendSystemPackageUpdatedBroadcastsInternal(); - } - } } } @@ -17715,12 +17368,12 @@ public class PackageManagerService extends IPackageManager.Stub String packageName = deletedPs.name; if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs); // Retrieve object to delete permissions for shared user later on - final PackageParser.Package deletedPkg = deletedPs.pkg; + final AndroidPackage deletedPkg = deletedPs.pkg; if (outInfo != null) { outInfo.removedPackage = packageName; outInfo.installerPackageName = deletedPs.installSource.installerPackageName; outInfo.isStaticSharedLib = deletedPkg != null - && deletedPkg.staticSharedLibName != null; + && deletedPkg.getStaticSharedLibName() != null; outInfo.populateUsers(deletedPs == null ? null : deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs); } @@ -17728,14 +17381,14 @@ public class PackageManagerService extends IPackageManager.Stub removePackageLI(deletedPs.name, (flags & PackageManager.DELETE_CHATTY) != 0); if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) { - final PackageParser.Package resolvedPkg; + final AndroidPackage resolvedPkg; if (deletedPkg != null) { resolvedPkg = deletedPkg; } else { // We don't have a parsed package when it lives on an ejected // adopted storage device, so fake something together - resolvedPkg = new PackageParser.Package(deletedPs.name); - resolvedPkg.setVolumeUuid(deletedPs.volumeUuid); + resolvedPkg = PackageImpl.buildFakeForDeletion(deletedPs.name, + deletedPs.volumeUuid); } destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL); @@ -17849,13 +17502,13 @@ public class PackageManagerService extends IPackageManager.Stub throws SystemDeleteException { final boolean applyUserRestrictions = (allUserHandles != null) && outInfo != null && (outInfo.origUsers != null); - final PackageParser.Package deletedPkg = deletedPs.pkg; + final AndroidPackage deletedPkg = deletedPs.pkg; // Confirm if the system package has been updated // An updated system app can be deleted. This will also have to restore // the system pkg from system partition // reader final PackageSetting disabledPs = action.disabledPs; - if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.packageName + if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName() + " disabledPs=" + disabledPs); Slog.d(TAG, "Deleting system pkg from data partition"); @@ -17872,21 +17525,6 @@ public class PackageManagerService extends IPackageManager.Stub if (outInfo != null) { // Delete the updated package outInfo.isRemovedPackageSystemUpdate = true; - if (outInfo.removedChildPackages != null) { - final int childCount = (deletedPs.childPackageNames != null) - ? deletedPs.childPackageNames.size() : 0; - for (int i = 0; i < childCount; i++) { - String childPackageName = deletedPs.childPackageNames.get(i); - if (disabledPs.childPackageNames != null && disabledPs.childPackageNames - .contains(childPackageName)) { - PackageRemovedInfo childInfo = outInfo.removedChildPackages.get( - childPackageName); - if (childInfo != null) { - childInfo.isRemovedPackageSystemUpdate = true; - } - } - } - } } if (disabledPs.versionCode < deletedPs.versionCode) { @@ -17898,7 +17536,7 @@ public class PackageManagerService extends IPackageManager.Stub } deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles, - outInfo, writeSettings, disabledPs.pkg); + outInfo, writeSettings); // writer synchronized (mLock) { @@ -17919,16 +17557,16 @@ public class PackageManagerService extends IPackageManager.Stub outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(), writeSettings); } catch (PackageManagerException e) { - Slog.w(TAG, "Failed to restore system package:" + deletedPkg.packageName + ": " + Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": " + e.getMessage()); // TODO(patb): can we avoid this; throw would come from scan... throw new SystemDeleteException(e); } finally { - if (disabledPs.pkg.isStub) { + if (disabledPs.pkg.isStub()) { // We've re-installed the stub; make sure it's disabled here. If package was // originally enabled, we'll install the compressed version of the application // and re-enable it afterward. - final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.packageName); + final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.getPackageName()); if (stubPs != null) { stubPs.setEnabled( COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android"); @@ -17940,7 +17578,7 @@ public class PackageManagerService extends IPackageManager.Stub /** * Installs a package that's already on the system partition. */ - private PackageParser.Package installPackageFromSystemLIF(@NonNull String codePathString, + private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString, @Nullable int[] allUserHandles, @Nullable int[] origUserHandles, @Nullable PermissionsState origPermissionState, boolean writeSettings) throws PackageManagerException { @@ -17961,7 +17599,7 @@ public class PackageManagerService extends IPackageManager.Stub } final File codePath = new File(codePathString); - final PackageParser.Package pkg = + final AndroidPackage pkg = scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null); try { @@ -17975,7 +17613,7 @@ public class PackageManagerService extends IPackageManager.Stub // writer synchronized (mLock) { - PackageSetting ps = mSettings.mPackages.get(pkg.packageName); + PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName()); // Propagate the permissions state as we do not want to drop on the floor // runtime permissions. The update permissions method below will take @@ -17983,7 +17621,7 @@ public class PackageManagerService extends IPackageManager.Stub if (origPermissionState != null) { ps.getPermissionsState().copyFrom(origPermissionState); } - mPermissionManager.updatePermissions(pkg.packageName, pkg); + mPermissionManager.updatePermissions(pkg.getPackageName(), pkg); final boolean applyUserRestrictions = (allUserHandles != null) && (origUserHandles != null); @@ -18021,58 +17659,22 @@ public class PackageManagerService extends IPackageManager.Stub private void deleteInstalledPackageLIF(PackageSetting ps, boolean deleteCodeAndResources, int flags, int[] allUserHandles, - PackageRemovedInfo outInfo, boolean writeSettings, - PackageParser.Package replacingPackage) { + PackageRemovedInfo outInfo, boolean writeSettings) { synchronized (mLock) { if (outInfo != null) { outInfo.uid = ps.appId; } - - if (outInfo != null && outInfo.removedChildPackages != null) { - final int childCount = (ps.childPackageNames != null) - ? ps.childPackageNames.size() : 0; - for (int i = 0; i < childCount; i++) { - String childPackageName = ps.childPackageNames.get(i); - PackageSetting childPs = mSettings.mPackages.get(childPackageName); - PackageRemovedInfo childInfo = outInfo.removedChildPackages.get( - childPackageName); - if (childInfo != null) { - childInfo.uid = childPs.appId; - } - } - } } // Delete package data from internal structures and also remove data if flag is set removePackageDataLIF(ps, allUserHandles, outInfo, flags, writeSettings); - // Delete the child packages data - final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageSetting childPs; - synchronized (mLock) { - childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i)); - } - if (childPs != null) { - PackageRemovedInfo childOutInfo = (outInfo != null - && outInfo.removedChildPackages != null) - ? outInfo.removedChildPackages.get(childPs.name) : null; - final int deleteFlags = (flags & DELETE_KEEP_DATA) != 0 - && (replacingPackage != null - && !replacingPackage.hasChildPackage(childPs.name)) - ? flags & ~DELETE_KEEP_DATA : flags; - removePackageDataLIF(childPs, allUserHandles, childOutInfo, - deleteFlags, writeSettings); - } - } - // Delete application code and resources only for parent packages - if (ps.parentPackageName == null) { - if (deleteCodeAndResources && (outInfo != null)) { - outInfo.args = createInstallArgsForExisting( - ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps)); - if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args); - } + if (deleteCodeAndResources && (outInfo != null)) { + outInfo.args = createInstallArgsForExisting( + ps.codePathString, ps.resourcePathString, getAppDexInstructionSets( + ps.primaryCpuAbiString, ps.secondaryCpuAbiString)); + if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args); } } @@ -18085,10 +17687,10 @@ public class PackageManagerService extends IPackageManager.Stub // Cannot block uninstall of static shared libs as they are // considered a part of the using app (emulating static linking). // Also static libs are installed always on internal storage. - PackageParser.Package pkg = mPackages.get(packageName); - if (pkg != null && pkg.staticSharedLibName != null) { + AndroidPackage pkg = mPackages.get(packageName); + if (pkg != null && pkg.getStaticSharedLibName() != null) { Slog.w(TAG, "Cannot block uninstall of package: " + packageName - + " providing static shared library: " + pkg.staticSharedLibName); + + " providing static shared library: " + pkg.getStaticSharedLibName()); return false; } mSettings.setBlockUninstallLPw(userId, packageName, blockUninstall); @@ -18152,40 +17754,22 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") private static DeletePackageAction mayDeletePackageLocked( PackageRemovedInfo outInfo, PackageSetting ps, @Nullable PackageSetting disabledPs, - @Nullable PackageSetting[] children, int flags, UserHandle user) { + int flags, UserHandle user) { if (ps == null) { return null; } if (isSystemApp(ps)) { - if (ps.parentPackageName != null) { - Slog.w(TAG, "Attempt to delete child system package " + ps.pkg.packageName); - return null; - } - final boolean deleteSystem = (flags & PackageManager.DELETE_SYSTEM_APP) != 0; final boolean deleteAllUsers = user == null || user.getIdentifier() == UserHandle.USER_ALL; if ((!deleteSystem || deleteAllUsers) && disabledPs == null) { - Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.packageName); + Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.getPackageName()); return null; } // Confirmed if the system package has been updated // An updated system app can be deleted. This will also have to restore // the system pkg from system partition reader } - final int parentReferenceCount = - (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0; - final int childCount = children != null ? children.length : 0; - if (childCount != parentReferenceCount) { - return null; - } - if (childCount != 0 && outInfo != null && outInfo.removedChildPackages != null) { - for (PackageSetting child : children) { - if (child == null || !ps.childPackageNames.contains(child.name)) { - return null; - } - } - } return new DeletePackageAction(ps, disabledPs, outInfo, flags, user); } @@ -18195,13 +17779,12 @@ public class PackageManagerService extends IPackageManager.Stub private boolean deletePackageLIF(@NonNull String packageName, UserHandle user, boolean deleteCodeAndResources, int[] allUserHandles, int flags, PackageRemovedInfo outInfo, boolean writeSettings, - PackageParser.Package replacingPackage) { + ParsedPackage replacingPackage) { final DeletePackageAction action; synchronized (mLock) { final PackageSetting ps = mSettings.mPackages.get(packageName); final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps); - PackageSetting[] children = mSettings.getChildSettingsLPr(ps); - action = mayDeletePackageLocked(outInfo, ps, disabledPs, children, flags, user); + action = mayDeletePackageLocked(outInfo, ps, disabledPs, flags, user); } if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user); if (null == action) { @@ -18232,30 +17815,13 @@ public class PackageManagerService extends IPackageManager.Stub private void executeDeletePackageLIF(DeletePackageAction action, String packageName, boolean deleteCodeAndResources, int[] allUserHandles, boolean writeSettings, - PackageParser.Package replacingPackage) throws SystemDeleteException { + ParsedPackage replacingPackage) throws SystemDeleteException { final PackageSetting ps = action.deletingPs; final PackageRemovedInfo outInfo = action.outInfo; final UserHandle user = action.user; final int flags = action.flags; final boolean systemApp = isSystemApp(ps); - if (ps.parentPackageName != null - && (!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) { - if (DEBUG_REMOVE) { - Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:" - + ((user == null) ? UserHandle.USER_ALL : user)); - } - final int removedUserId = (user != null) ? user.getIdentifier() - : UserHandle.USER_ALL; - - clearPackageStateForUserLIF(ps, removedUserId, outInfo, flags); - synchronized (mLock) { - markPackageUninstalledForUserLPw(ps, user); - scheduleWritePackageRestrictionsLocked(user); - } - return; - } - final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier(); if (ps.getPermissionsState().hasPermission(Manifest.permission.SUSPEND_APPS, userId)) { unsuspendForSuspendingPackage(packageName, userId); @@ -18305,26 +17871,6 @@ public class PackageManagerService extends IPackageManager.Stub } } - // If we are deleting a composite package for all users, keep track - // of result for each child. - if (ps.childPackageNames != null && outInfo != null) { - synchronized (mLock) { - final int childCount = ps.childPackageNames.size(); - outInfo.removedChildPackages = new ArrayMap<>(childCount); - for (int i = 0; i < childCount; i++) { - String childPackageName = ps.childPackageNames.get(i); - PackageRemovedInfo childInfo = new PackageRemovedInfo(this); - childInfo.removedPackage = childPackageName; - childInfo.installerPackageName = ps.installSource.installerPackageName; - outInfo.removedChildPackages.put(childPackageName, childInfo); - PackageSetting childPs = mSettings.getPackageLPr(childPackageName); - if (childPs != null) { - childInfo.origUsers = childPs.queryInstalledUsers(allUserHandles, true); - } - } - } - } - // TODO(b/109941548): break reasons for ret = false out into mayDelete method if (systemApp) { if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name); @@ -18334,53 +17880,12 @@ public class PackageManagerService extends IPackageManager.Stub } else { if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name); deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles, - outInfo, writeSettings, replacingPackage); + outInfo, writeSettings); } // Take a note whether we deleted the package for all users if (outInfo != null) { outInfo.removedForAllUsers = mPackages.get(ps.name) == null; - if (outInfo.removedChildPackages != null) { - synchronized (mLock) { - final int childCount = outInfo.removedChildPackages.size(); - for (int i = 0; i < childCount; i++) { - PackageRemovedInfo childInfo = outInfo.removedChildPackages.valueAt(i); - if (childInfo != null) { - childInfo.removedForAllUsers = mPackages.get( - childInfo.removedPackage) == null; - } - } - } - } - // If we uninstalled an update to a system app there may be some - // child packages that appeared as they are declared in the system - // app but were not declared in the update. - if (systemApp) { - synchronized (mLock) { - PackageSetting updatedPs = mSettings.getPackageLPr(ps.name); - final int childCount = (updatedPs.childPackageNames != null) - ? updatedPs.childPackageNames.size() : 0; - for (int i = 0; i < childCount; i++) { - String childPackageName = updatedPs.childPackageNames.get(i); - if (outInfo.removedChildPackages == null - || outInfo.removedChildPackages.indexOfKey(childPackageName) < 0) { - PackageSetting childPs = mSettings.getPackageLPr(childPackageName); - if (childPs == null) { - continue; - } - PackageInstalledInfo installRes = new PackageInstalledInfo(); - installRes.name = childPackageName; - installRes.newUsers = childPs.queryInstalledUsers(allUserHandles, true); - installRes.pkg = mPackages.get(childPackageName); - installRes.uid = childPs.pkg.applicationInfo.uid; - if (outInfo.appearedChildPackages == null) { - outInfo.appearedChildPackages = new ArrayMap<>(); - } - outInfo.appearedChildPackages.put(childPackageName, installRes); - } - } - } - } } } @@ -18414,7 +17919,7 @@ public class PackageManagerService extends IPackageManager.Stub private void clearPackageStateForUserLIF(PackageSetting ps, int userId, PackageRemovedInfo outInfo, int flags) { - final PackageParser.Package pkg; + final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(ps.name); } @@ -18456,7 +17961,7 @@ public class PackageManagerService extends IPackageManager.Stub if (outInfo != null) { outInfo.removedPackage = ps.name; outInfo.installerPackageName = ps.installSource.installerPackageName; - outInfo.isStaticSharedLib = pkg != null && pkg.staticSharedLibName != null; + outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null; outInfo.removedAppId = ps.appId; outInfo.removedUsers = userIds; outInfo.broadcastUsers = userIds; @@ -18467,7 +17972,7 @@ public class PackageManagerService extends IPackageManager.Stub public void clearApplicationProfileData(String packageName) { enforceSystemOrRoot("Only the system can clear all profile data"); - final PackageParser.Package pkg; + final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); } @@ -18545,7 +18050,7 @@ public class PackageManagerService extends IPackageManager.Stub } // Try finding details about the requested package - PackageParser.Package pkg; + AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); if (pkg == null) { @@ -18564,7 +18069,7 @@ public class PackageManagerService extends IPackageManager.Stub clearAppDataLIF(pkg, userId, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL); - final int appId = UserHandle.getAppId(pkg.applicationInfo.uid); + final int appId = UserHandle.getAppId(pkg.getUid()); removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), userId, appId); UserManagerInternal umInternal = mInjector.getUserManagerInternal(); @@ -18641,14 +18146,14 @@ public class PackageManagerService extends IPackageManager.Stub final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission( android.Manifest.permission.ACCESS_INSTANT_APPS); - final PackageParser.Package pkg; + final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); } // Queue up an async operation since the package deletion may take a little while. mHandler.post(() -> { - final PackageSetting ps = pkg == null ? null : (PackageSetting) pkg.mExtras; + final PackageSetting ps = pkg == null ? null : getPackageSetting(pkg.getPackageName()); boolean doClearData = true; if (ps != null) { final boolean targetIsInstantApp = @@ -18728,7 +18233,7 @@ public class PackageManagerService extends IPackageManager.Stub while (it.hasNext()) { final PackageSetting ps = it.next(); if (ps.pkg != null) { - int v = ps.pkg.applicationInfo.targetSdkVersion; + int v = ps.pkg.getTargetSdkVersion(); if (v < vers) vers = v; } } @@ -18736,7 +18241,7 @@ public class PackageManagerService extends IPackageManager.Stub } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (ps.pkg != null) { - return ps.pkg.applicationInfo.targetSdkVersion; + return ps.pkg.getTargetSdkVersion(); } } return Build.VERSION_CODES.CUR_DEVELOPMENT; @@ -18744,9 +18249,9 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") private int getPackageTargetSdkVersionLockedLPr(String packageName) { - final PackageParser.Package p = mPackages.get(packageName); + final AndroidPackage p = mPackages.get(packageName); if (p != null) { - return p.applicationInfo.targetSdkVersion; + return p.getTargetSdkVersion(); } return Build.VERSION_CODES.CUR_DEVELOPMENT; } @@ -18915,7 +18420,7 @@ public class PackageManagerService extends IPackageManager.Stub } // writer synchronized (mLock) { - PackageParser.Package pkg = mPackages.get(packageName); + AndroidPackage pkg = mPackages.get(packageName); if (pkg == null || !isCallerSameApp(packageName, callingUid)) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) @@ -18989,8 +18494,8 @@ public class PackageManagerService extends IPackageManager.Stub private void clearIntentFilterVerificationsLPw(int userId) { final int packageCount = mPackages.size(); for (int i = 0; i < packageCount; i++) { - PackageParser.Package pkg = mPackages.valueAt(i); - clearIntentFilterVerificationsLPw(pkg.packageName, userId); + AndroidPackage pkg = mPackages.valueAt(i); + clearIntentFilterVerificationsLPw(pkg.getPackageName(), userId); } } @@ -19938,8 +19443,8 @@ public class PackageManagerService extends IPackageManager.Stub // If we're enabling a system stub, there's a little more work to do. // Prior to enabling the package, we need to decompress the APK(s) to the // data partition and then replace the version on the system partition. - final PackageParser.Package deletedPkg = pkgSetting.pkg; - final boolean isSystemStub = deletedPkg.isStub + final AndroidPackage deletedPkg = pkgSetting.pkg; + final boolean isSystemStub = deletedPkg.isStub() && deletedPkg.isSystem(); if (isSystemStub && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT @@ -19960,10 +19465,10 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { // We're dealing with a component level state change // First, verify that this is a valid class name. - PackageParser.Package pkg = pkgSetting.pkg; + AndroidPackage pkg = pkgSetting.pkg; if (pkg == null || !pkg.hasComponentClassName(className)) { if (pkg != null && - pkg.applicationInfo.targetSdkVersion >= + pkg.getTargetSdkVersion() >= Build.VERSION_CODES.JELLY_BEAN) { throw new IllegalArgumentException("Component class " + className + " does not exist in " + packageName); @@ -20371,7 +19876,7 @@ public class PackageManagerService extends IPackageManager.Stub storage.registerListener(mStorageListener); mInstallerService.systemReady(); - mApexManager.systemReady(); + mApexManager.systemReady(mContext); mPackageDexOptimizer.systemReady(); mInjector.getStorageManagerInternal().addExternalStoragePolicy( @@ -20428,14 +19933,14 @@ public class PackageManagerService extends IPackageManager.Stub if (packageName == null) { return; } - PackageParser.Package pkg = mPackages.get(packageName); + AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { return; } - sendPackageChangedBroadcast(pkg.packageName, + sendPackageChangedBroadcast(pkg.getPackageName(), true /* dontKillApp */, - new ArrayList<>(Collections.singletonList(pkg.packageName)), - pkg.applicationInfo.uid, + new ArrayList<>(Collections.singletonList(pkg.getPackageName())), + pkg.getUid(), Intent.ACTION_OVERLAY_CHANGED); } }, overlayFilter); @@ -21024,7 +20529,7 @@ public class PackageManagerService extends IPackageManager.Stub if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS) && packageName == null) { - mComponentResolver.dumpServicePermissions(pw, dumpState, packageName); + mComponentResolver.dumpServicePermissions(pw, dumpState); } if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) { @@ -21167,9 +20672,9 @@ public class PackageManagerService extends IPackageManager.Stub ipw.println(); ipw.println("Dexopt state:"); ipw.increaseIndent(); - Collection<PackageParser.Package> packages; + Collection<AndroidPackage> packages; if (packageName != null) { - PackageParser.Package targetPackage = mPackages.get(packageName); + AndroidPackage targetPackage = mPackages.get(packageName); if (targetPackage != null) { packages = Collections.singletonList(targetPackage); } else { @@ -21180,11 +20685,11 @@ public class PackageManagerService extends IPackageManager.Stub packages = mPackages.values(); } - for (PackageParser.Package pkg : packages) { - ipw.println("[" + pkg.packageName + "]"); + for (AndroidPackage pkg : packages) { + ipw.println("[" + pkg.getPackageName() + "]"); ipw.increaseIndent(); mPackageDexOptimizer.dumpDexoptState(ipw, pkg, - mDexManager.getPackageUseInfoOrDefault(pkg.packageName)); + mDexManager.getPackageUseInfoOrDefault(pkg.getPackageName())); ipw.decreaseIndent(); } } @@ -21196,9 +20701,9 @@ public class PackageManagerService extends IPackageManager.Stub ipw.println(); ipw.println("Compiler stats:"); ipw.increaseIndent(); - Collection<PackageParser.Package> packages; + Collection<AndroidPackage> packages; if (packageName != null) { - PackageParser.Package targetPackage = mPackages.get(packageName); + AndroidPackage targetPackage = mPackages.get(packageName); if (targetPackage != null) { packages = Collections.singletonList(targetPackage); } else { @@ -21209,11 +20714,11 @@ public class PackageManagerService extends IPackageManager.Stub packages = mPackages.values(); } - for (PackageParser.Package pkg : packages) { - ipw.println("[" + pkg.packageName + "]"); + for (AndroidPackage pkg : packages) { + ipw.println("[" + pkg.getPackageName() + "]"); ipw.increaseIndent(); - CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.packageName); + CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.getPackageName()); if (stats == null) { ipw.println("(No recorded stats)"); } else { @@ -21284,14 +20789,14 @@ public class PackageManagerService extends IPackageManager.Stub } private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, - ArrayList<ApplicationInfo> infos, IIntentReceiver finishedReceiver) { - final int size = infos.size(); + ArrayList<AndroidPackage> packages, IIntentReceiver finishedReceiver) { + final int size = packages.size(); final String[] packageNames = new String[size]; final int[] packageUids = new int[size]; for (int i = 0; i < size; i++) { - final ApplicationInfo info = infos.get(i); - packageNames[i] = info.packageName; - packageUids[i] = info.uid; + final AndroidPackage pkg = packages.get(i); + packageNames[i] = pkg.getAppInfoPackageName(); + packageUids[i] = pkg.getUid(); } sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids, finishedReceiver); @@ -21334,7 +20839,7 @@ public class PackageManagerService extends IPackageManager.Stub } final ArrayList<PackageFreezer> freezers = new ArrayList<>(); - final ArrayList<ApplicationInfo> loaded = new ArrayList<>(); + final ArrayList<AndroidPackage> loaded = new ArrayList<>(); final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE; final VersionInfo ver; @@ -21347,10 +20852,10 @@ public class PackageManagerService extends IPackageManager.Stub for (PackageSetting ps : packages) { freezers.add(freezePackage(ps.name, "loadPrivatePackagesInner")); synchronized (mInstallLock) { - final PackageParser.Package pkg; + final AndroidPackage pkg; try { pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0, null); - loaded.add(pkg.applicationInfo); + loaded.add(pkg); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage()); @@ -21422,14 +20927,14 @@ public class PackageManagerService extends IPackageManager.Stub return; } - final ArrayList<ApplicationInfo> unloaded = new ArrayList<>(); + final ArrayList<AndroidPackage> unloaded = new ArrayList<>(); synchronized (mInstallLock) { synchronized (mLock) { final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(volumeUuid); for (PackageSetting ps : packages) { if (ps.pkg == null) continue; - final ApplicationInfo info = ps.pkg.applicationInfo; + final AndroidPackage pkg = ps.pkg; final int deleteFlags = PackageManager.DELETE_KEEP_DATA; final PackageRemovedInfo outInfo = new PackageRemovedInfo(this); @@ -21437,7 +20942,7 @@ public class PackageManagerService extends IPackageManager.Stub "unloadPrivatePackagesInner")) { if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo, false, null)) { - unloaded.add(info); + unloaded.add(pkg); } else { Slog.w(TAG, "Failed to unload " + ps.codePath); } @@ -21652,7 +21157,7 @@ public class PackageManagerService extends IPackageManager.Stub continue; } // Skip non-core apps if requested - if (onlyCoreApps && !ps.pkg.coreApp) { + if (onlyCoreApps && !ps.pkg.isCoreApp()) { result.add(packageName); continue; } @@ -21679,10 +21184,10 @@ public class PackageManagerService extends IPackageManager.Stub * <p> * <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em> */ - private void prepareAppDataAfterInstallLIF(PackageParser.Package pkg) { + private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) { final PackageSetting ps; synchronized (mLock) { - ps = mSettings.mPackages.get(pkg.packageName); + ps = mSettings.mPackages.get(pkg.getPackageName()); mSettings.writeKernelMappingLPr(ps); } @@ -21712,19 +21217,15 @@ public class PackageManagerService extends IPackageManager.Stub * will try recovering system apps by wiping data; third-party app data is * left intact. */ - private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) { + private void prepareAppDataLIF(AndroidPackage pkg, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } prepareAppDataLeafLIF(pkg, userId, flags); - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags); - } } - private void prepareAppDataAndMigrateLIF(PackageParser.Package pkg, int userId, int flags, + private void prepareAppDataAndMigrateLIF(AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) { prepareAppDataLIF(pkg, userId, flags); @@ -21735,43 +21236,37 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) { + private void prepareAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) { if (DEBUG_APP_DATA) { - Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x" + Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x" + Integer.toHexString(flags)); } final PackageSetting ps; synchronized (mLock) { - ps = mSettings.mPackages.get(pkg.packageName); - } - final String volumeUuid = pkg.volumeUuid; - final String packageName = pkg.packageName; - - ApplicationInfo app = (ps == null) - ? pkg.applicationInfo - : PackageParser.generateApplicationInfo(pkg, 0, ps.readUserState(userId), userId); - if (app == null) { - app = pkg.applicationInfo; + ps = mSettings.mPackages.get(pkg.getPackageName()); } + final String volumeUuid = pkg.getVolumeUuid(); + final String packageName = pkg.getPackageName(); - final int appId = UserHandle.getAppId(app.uid); + final int appId = UserHandle.getAppId(pkg.getUid()); - Preconditions.checkNotNull(app.seInfo); + Preconditions.checkNotNull(pkg.getSeInfo()); - final String seInfo = app.seInfo + (app.seInfoUser != null ? app.seInfoUser : ""); + final String seInfo = + pkg.getSeInfo() + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : ""); long ceDataInode = -1; try { ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, - appId, seInfo, app.targetSdkVersion); + appId, seInfo, pkg.getTargetSdkVersion()); } catch (InstallerException e) { - if (app.isSystemApp()) { + if (pkg.isSystemApp()) { logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName + ", but trying to recover: " + e); destroyAppDataLeafLIF(pkg, userId, flags); try { ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, - appId, seInfo, app.targetSdkVersion); + appId, seInfo, pkg.getTargetSdkVersion()); logCriticalInfo(Log.DEBUG, "Recovery succeeded!"); } catch (InstallerException e2) { logCriticalInfo(Log.DEBUG, "Recovery failed!"); @@ -21813,29 +21308,24 @@ public class PackageManagerService extends IPackageManager.Stub prepareAppDataContentsLeafLIF(pkg, userId, flags); } - private void prepareAppDataContentsLIF(PackageParser.Package pkg, int userId, int flags) { + private void prepareAppDataContentsLIF(AndroidPackage pkg, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } prepareAppDataContentsLeafLIF(pkg, userId, flags); - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - prepareAppDataContentsLeafLIF(pkg.childPackages.get(i), userId, flags); - } } - private void prepareAppDataContentsLeafLIF(PackageParser.Package pkg, int userId, int flags) { - final String volumeUuid = pkg.volumeUuid; - final String packageName = pkg.packageName; - final ApplicationInfo app = pkg.applicationInfo; + private void prepareAppDataContentsLeafLIF(AndroidPackage pkg, int userId, int flags) { + final String volumeUuid = pkg.getVolumeUuid(); + final String packageName = pkg.getPackageName(); if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { // Create a native library symlink only if we have native libraries // and if the native libraries are 32 bit libraries. We do not provide // this symlink for 64 bit libraries. - if (app.primaryCpuAbi != null && !VMRuntime.is64BitAbi(app.primaryCpuAbi)) { - final String nativeLibPath = app.nativeLibraryDir; + if (pkg.getPrimaryCpuAbi() != null && !VMRuntime.is64BitAbi(pkg.getPrimaryCpuAbi())) { + final String nativeLibPath = pkg.getNativeLibraryDir(); try { mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName, nativeLibPath, userId); @@ -21851,17 +21341,17 @@ public class PackageManagerService extends IPackageManager.Stub * CE/DE data to match the {@code defaultToDeviceProtectedStorage} flag * requested by the app. */ - private boolean maybeMigrateAppDataLIF(PackageParser.Package pkg, int userId) { + private boolean maybeMigrateAppDataLIF(AndroidPackage pkg, int userId) { if (pkg.isSystem() && !StorageManager.isFileEncryptedNativeOrEmulated() && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { - final int storageTarget = pkg.applicationInfo.isDefaultToDeviceProtectedStorage() + final int storageTarget = pkg.isDefaultToDeviceProtectedStorage() ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE; try { - mInstaller.migrateAppData(pkg.volumeUuid, pkg.packageName, userId, + mInstaller.migrateAppData(pkg.getVolumeUuid(), pkg.getPackageName(), userId, storageTarget); } catch (InstallerException e) { logCriticalInfo(Log.WARN, - "Failed to migrate " + pkg.packageName + ": " + e.getMessage()); + "Failed to migrate " + pkg.getPackageName() + ": " + e.getMessage()); } return true; } else { @@ -21912,7 +21402,6 @@ public class PackageManagerService extends IPackageManager.Stub */ private class PackageFreezer implements AutoCloseable { private final String mPackageName; - private final PackageFreezer[] mChildren; private final boolean mWeFroze; @@ -21927,7 +21416,6 @@ public class PackageManagerService extends IPackageManager.Stub */ public PackageFreezer() { mPackageName = null; - mChildren = null; mWeFroze = false; mCloseGuard.open("close"); } @@ -21941,18 +21429,6 @@ public class PackageManagerService extends IPackageManager.Stub if (ps != null) { killApplication(ps.name, ps.appId, userId, killReason); } - - final PackageParser.Package p = mPackages.get(packageName); - if (p != null && p.childPackages != null) { - final int N = p.childPackages.size(); - mChildren = new PackageFreezer[N]; - for (int i = 0; i < N; i++) { - mChildren[i] = new PackageFreezer(p.childPackages.get(i).packageName, - userId, killReason); - } - } else { - mChildren = null; - } } mCloseGuard.open("close"); } @@ -21975,12 +21451,6 @@ public class PackageManagerService extends IPackageManager.Stub if (mWeFroze) { mFrozenPackages.remove(mPackageName); } - - if (mChildren != null) { - for (PackageFreezer freezer : mChildren) { - freezer.close(); - } - } } } } @@ -22035,14 +21505,14 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); final PackageSetting ps = mSettings.mPackages.get(packageName); if (pkg == null || ps == null || shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) { throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package"); } - if (pkg.applicationInfo.isSystemApp()) { + if (pkg.isSystemApp()) { throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE, "Cannot move system application"); } @@ -22057,7 +21527,7 @@ public class PackageManagerService extends IPackageManager.Stub currentVolumeUuid = ps.volumeUuid; - final File probe = new File(pkg.codePath); + final File probe = new File(pkg.getCodePath()); final File probeOat = new File(probe, "oat"); if (!probe.isDirectory() || !probeOat.isDirectory()) { throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, @@ -22068,7 +21538,7 @@ public class PackageManagerService extends IPackageManager.Stub throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, "Package already moved to " + volumeUuid); } - if (pkg.applicationInfo.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) { + if (pkg.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) { throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN, "Device admin cannot be moved"); } @@ -22079,13 +21549,13 @@ public class PackageManagerService extends IPackageManager.Stub } isCurrentLocationExternal = isExternal(pkg); - codeFile = new File(pkg.codePath); + codeFile = new File(pkg.getCodePath()); installSource = ps.installSource; packageAbiOverride = ps.cpuAbiOverrideString; - appId = UserHandle.getAppId(pkg.applicationInfo.uid); - seinfo = pkg.applicationInfo.seInfo; - label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo)); - targetSdkVersion = pkg.applicationInfo.targetSdkVersion; + appId = UserHandle.getAppId(pkg.getUid()); + seinfo = pkg.getSeInfo(); + label = String.valueOf(pm.getApplicationLabel(pkg.toAppInfoWithoutState())); + targetSdkVersion = pkg.getTargetSdkVersion(); freezer = freezePackage(packageName, "movePackageInternal"); installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true); } @@ -22246,7 +21716,7 @@ public class PackageManagerService extends IPackageManager.Stub * @param packageName The package that was moved. */ private void logAppMovedStorage(String packageName, boolean isPreviousLocationExternal) { - final PackageParser.Package pkg; + final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); } @@ -22254,8 +21724,8 @@ public class PackageManagerService extends IPackageManager.Stub return; } - final StorageManager storage = mInjector.getStorageManager(); - VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString()); + final StorageManager storage = mInjector.getStorageManager();; + VolumeInfo volume = storage.findVolumeByUuid(pkg.getStorageUuid().toString()); int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg)); if (!isPreviousLocationExternal && isExternal(pkg)) { @@ -22369,10 +21839,10 @@ public class PackageManagerService extends IPackageManager.Stub if (ps.pkg == null) { continue; } - final String packageName = ps.pkg.packageName; + final String packageName = ps.pkg.getPackageName(); // Skip over if system app or static shared library if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0 - || !TextUtils.isEmpty(ps.pkg.staticSharedLibName)) { + || !TextUtils.isEmpty(ps.pkg.getStaticSharedLibName())) { continue; } if (DEBUG_CLEAN_APKS) { @@ -22499,13 +21969,13 @@ public class PackageManagerService extends IPackageManager.Stub if (packageName == null || alias == null) { return null; } - synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(packageName); + synchronized(mLock) { + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (shouldFilterApplicationLocked( ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) { Slog.w(TAG, "KeySet requested for filtered package: " + packageName); @@ -22524,19 +21994,19 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { // filter and pretend the package doesn't exist Slog.w(TAG, "KeySet requested for filtered package: " + packageName + ", uid:" + callingUid); throw new IllegalArgumentException("Unknown package: " + packageName); } - if (pkg.applicationInfo.uid != callingUid + if (pkg.getUid() != callingUid && Process.SYSTEM_UID != callingUid) { throw new SecurityException("May not access signing KeySet of other apps."); } @@ -22554,11 +22024,11 @@ public class PackageManagerService extends IPackageManager.Stub if (packageName == null || ks == null) { return false; } - synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(packageName); + synchronized(mLock) { + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null - || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid, - UserHandle.getUserId(callingUid))) { + || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()), + callingUid, UserHandle.getUserId(callingUid))) { Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } @@ -22581,10 +22051,10 @@ public class PackageManagerService extends IPackageManager.Stub return false; } synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null - || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid, - UserHandle.getUserId(callingUid))) { + || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()), + callingUid, UserHandle.getUserId(callingUid))) { Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } @@ -22616,29 +22086,29 @@ public class PackageManagerService extends IPackageManager.Stub * Check and throw if the given before/after packages would be considered a * downgrade. */ - private static void checkDowngrade(PackageParser.Package before, PackageInfoLite after) + private static void checkDowngrade(AndroidPackage before, PackageInfoLite after) throws PackageManagerException { if (after.getLongVersionCode() < before.getLongVersionCode()) { throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE, "Update version code " + after.versionCode + " is older than current " + before.getLongVersionCode()); } else if (after.getLongVersionCode() == before.getLongVersionCode()) { - if (after.baseRevisionCode < before.baseRevisionCode) { + if (after.baseRevisionCode < before.getBaseRevisionCode()) { throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE, "Update base revision code " + after.baseRevisionCode - + " is older than current " + before.baseRevisionCode); + + " is older than current " + before.getBaseRevisionCode()); } if (!ArrayUtils.isEmpty(after.splitNames)) { for (int i = 0; i < after.splitNames.length; i++) { final String splitName = after.splitNames[i]; - final int j = ArrayUtils.indexOf(before.splitNames, splitName); + final int j = ArrayUtils.indexOf(before.getSplitNames(), splitName); if (j != -1) { - if (after.splitRevisionCodes[i] < before.splitRevisionCodes[j]) { + if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) { throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE, "Update split " + splitName + " revision code " + after.splitRevisionCodes[i] + " is older than current " - + before.splitRevisionCodes[j]); + + before.getSplitRevisionCodes()[j]); } } } @@ -22828,13 +22298,13 @@ public class PackageManagerService extends IPackageManager.Stub if (packageSetting == null) { return false; } - PackageParser.Package pkg = packageSetting.pkg; + AndroidPackage pkg = packageSetting.pkg; if (pkg == null) { // May happen if package in on a removable sd card return false; } - return pkg.mSigningDetails.hasAncestorOrSelf(mPlatformPackage.mSigningDetails) - || mPlatformPackage.mSigningDetails.checkCapability(pkg.mSigningDetails, + return pkg.getSigningDetails().hasAncestorOrSelf(mPlatformPackage.getSigningDetails()) + || mPlatformPackage.getSigningDetails().checkCapability(pkg.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.PERMISSION); } @@ -22870,11 +22340,11 @@ public class PackageManagerService extends IPackageManager.Stub private SigningDetails getSigningDetails(@NonNull String packageName) { synchronized (mLock) { - PackageParser.Package p = mPackages.get(packageName); + AndroidPackage p = mPackages.get(packageName); if (p == null) { return null; } - return p.mSigningDetails; + return p.getSigningDetails(); } } @@ -22905,28 +22375,25 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public boolean filterAppAccess(PackageParser.Package pkg, int callingUid, int userId) { + public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) { synchronized (mLock) { - return PackageManagerService.this.shouldFilterApplicationLocked( - (PackageSetting) pkg.mExtras, callingUid, userId); + PackageSetting ps = getPackageSetting(pkg.getPackageName()); + return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid, + userId); } } @Override public boolean filterAppAccess(String packageName, int callingUid, int userId) { synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(packageName); - if (pkg == null) { - return false; - } - return PackageManagerService.this - .shouldFilterApplicationLocked( - (PackageSetting) pkg.mExtras, callingUid, userId); + PackageSetting ps = getPackageSetting(packageName); + return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid, + userId); } } @Override - public PackageParser.Package getPackage(String packageName) { + public AndroidPackage getPackage(String packageName) { synchronized (mLock) { packageName = resolveInternalPackageNameLPr( packageName, PackageManager.VERSION_CODE_HIGHEST); @@ -22935,10 +22402,10 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public PackageParser.Package getPackage(int uid) { + public AndroidPackage getPackage(int uid) { synchronized (mLock) { final String[] packageNames = getPackagesForUid(uid); - PackageParser.Package pkg = null; + AndroidPackage pkg = null; final int numPackages = packageNames == null ? 0 : packageNames.length; for (int i = 0; pkg == null && i < numPackages; i++) { pkg = mPackages.get(packageNames[i]); @@ -22947,6 +22414,12 @@ public class PackageManagerService extends IPackageManager.Stub } } + @Nullable + @Override + public PackageSetting getPackageSetting(String packageName) { + return PackageManagerService.this.getPackageSetting(packageName); + } + @Override public PackageList getPackageList(PackageListObserver observer) { synchronized (mLock) { @@ -22971,17 +22444,19 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public PackageParser.Package getDisabledSystemPackage(String packageName) { + public Object getDisabledSystemPackage(@NonNull String packageName) { synchronized (mLock) { - final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName); - return (ps != null) ? ps.pkg : null; + return mSettings.getDisabledSystemPkgLPr(packageName); } } @Override - public @Nullable String getDisabledSystemPackageName(@NonNull String packageName) { - PackageParser.Package pkg = getDisabledSystemPackage(packageName); - return pkg == null ? null : pkg.packageName; + public @Nullable + String getDisabledSystemPackageName(@NonNull String packageName) { + PackageSetting disabledPkgSetting = (PackageSetting) getDisabledSystemPackage( + packageName); + AndroidPackage disabledPkg = disabledPkgSetting == null ? null : disabledPkgSetting.pkg; + return disabledPkg == null ? null : disabledPkg.getPackageName(); } /** @@ -23005,7 +22480,7 @@ public class PackageManagerService extends IPackageManager.Stub continue; } - PackageParser.Package pkg = getPackage(pkgName); + AndroidPackage pkg = getPackage(pkgName); if (pkg == null) { Log.w(TAG, "Could not find package " + pkgName); continue; @@ -23094,7 +22569,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean isPermissionsReviewRequired(String packageName, int userId) { synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { return false; } @@ -23280,9 +22755,10 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public boolean isEnabledAndMatches(ComponentInfo info, int flags, int userId) { + public boolean isEnabledAndMatches(ParsedComponent component, int flags, int userId) { synchronized (mLock) { - return mSettings.isEnabledAndMatchLPr(info, flags, userId); + AndroidPackage pkg = getPackage(component.getPackageName()); + return mSettings.isEnabledAndMatchLPr(pkg, component, flags, userId); } } @@ -23299,10 +22775,10 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public boolean setInstalled(PackageParser.Package pkg, @UserIdInt int userId, + public boolean setInstalled(AndroidPackage pkg, @UserIdInt int userId, boolean installed) { synchronized (mLock) { - final PackageSetting ps = mSettings.mPackages.get(pkg.packageName); + final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName()); if (ps.getInstalled(userId) != installed) { ps.setInstalled(installed, userId); return true; @@ -23324,16 +22800,15 @@ public class PackageManagerService extends IPackageManager.Stub public void grantImplicitAccess(int userId, Intent intent, int callingUid, int targetAppId) { synchronized (mLock) { - final PackageParser.Package callingPackage = getPackage(callingUid); + final AndroidPackage callingPackage = getPackage(callingUid); final int targetUid = UserHandle.getUid(userId, targetAppId); - final PackageParser.Package targetPackage = - getPackage(targetUid); + final AndroidPackage targetPackage = getPackage(targetUid); if (callingPackage == null || targetPackage == null) { return; } - final boolean instantApp = isInstantAppInternal(callingPackage.packageName, userId, - callingUid); + final boolean instantApp = isInstantAppInternal(callingPackage.getPackageName(), + userId, callingUid); if (instantApp) { mInstantAppRegistry.grantInstantAccessLPw(userId, intent, UserHandle.getAppId(callingUid), targetAppId); @@ -23370,9 +22845,9 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean isPackagePersistent(String packageName) { synchronized (mLock) { - PackageParser.Package pkg = mPackages.get(packageName); + AndroidPackage pkg = mPackages.get(packageName); return pkg != null - ? ((pkg.applicationInfo.flags&(ApplicationInfo.FLAG_SYSTEM + ? ((pkg.getFlags() & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT)) == (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT)) : false; @@ -23380,9 +22855,9 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public boolean isLegacySystemApp(PackageParser.Package pkg) { + public boolean isLegacySystemApp(AndroidPackage pkg) { synchronized (mLock) { - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); return mPromoteSystemApps && ps.isSystem() && mExistingSystemPackages.contains(ps.name); @@ -23393,9 +22868,10 @@ public class PackageManagerService extends IPackageManager.Stub public List<PackageInfo> getOverlayPackages(int userId) { final ArrayList<PackageInfo> overlayPackages = new ArrayList<PackageInfo>(); synchronized (mLock) { - for (PackageParser.Package p : mPackages.values()) { - if (p.mOverlayTarget != null) { - PackageInfo pkg = generatePackageInfo((PackageSetting)p.mExtras, 0, userId); + for (AndroidPackage p : mPackages.values()) { + if (p.getOverlayTarget() != null) { + PackageInfo pkg = generatePackageInfo(getPackageSetting(p.getPackageName()), + 0, userId); if (pkg != null) { overlayPackages.add(pkg); } @@ -23409,9 +22885,9 @@ public class PackageManagerService extends IPackageManager.Stub public List<String> getTargetPackageNames(int userId) { List<String> targetPackages = new ArrayList<>(); synchronized (mLock) { - for (PackageParser.Package p : mPackages.values()) { - if (p.mOverlayTarget == null) { - targetPackages.add(p.packageName); + for (AndroidPackage p : mPackages.values()) { + if (p.getOverlayTarget() == null) { + targetPackages.add(p.getPackageName()); } } } @@ -23432,12 +22908,12 @@ public class PackageManagerService extends IPackageManager.Stub overlayPaths = new ArrayList<>(N); for (int i = 0; i < N; i++) { final String packageName = overlayPackageNames.get(i); - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { Slog.e(TAG, "failed to find package " + packageName); return false; } - overlayPaths.add(pkg.baseCodePath); + overlayPaths.add(pkg.getBaseCodePath()); } } @@ -23555,12 +23031,12 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public void forEachPackage(Consumer<PackageParser.Package> actionLocked) { + public void forEachPackage(Consumer<AndroidPackage> actionLocked) { PackageManagerService.this.forEachPackage(actionLocked); } @Override - public void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked, + public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId) { PackageManagerService.this.forEachInstalledPackage(actionLocked, userId); } @@ -23609,7 +23085,7 @@ public class PackageManagerService extends IPackageManager.Stub */ @Override public boolean compileLayouts(String packageName) { - PackageParser.Package pkg; + AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); if (pkg == null) { @@ -23716,12 +23192,12 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean isCallerInstallerOfRecord( - @NonNull PackageParser.Package pkg, int callingUid) { + @NonNull AndroidPackage pkg, int callingUid) { synchronized (mLock) { if (pkg == null) { return false; } - final PackageSetting packageSetting = (PackageSetting) pkg.mExtras; + final PackageSetting packageSetting = getPackageSetting(pkg.getPackageName()); if (packageSetting == null) { return false; } @@ -23750,6 +23226,14 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writeLPr(); } } + + @Override + public void setIntegrityVerificationResult(int verificationId, int verificationResult) { + final Message msg = mHandler.obtainMessage(INTEGRITY_VERIFICATION_COMPLETE); + msg.arg1 = verificationId; + msg.obj = verificationResult; + mHandler.sendMessage(msg); + } } @GuardedBy("mLock") @@ -23784,11 +23268,12 @@ public class PackageManagerService extends IPackageManager.Stub PackageSetting ps = it.next(); if (ps.getInstalled(userId)) { res[i++] = ps.name; - } else { - res = ArrayUtils.removeElement(String.class, res, res[i]); } } - return res; + res = ArrayUtils.trimToSize(res, i); + if (res != null) { + return res; + } } catch (PackageManagerException e) { // Should not happen } @@ -23818,7 +23303,16 @@ public class PackageManagerService extends IPackageManager.Stub } } - void forEachPackage(Consumer<PackageParser.Package> actionLocked) { + @Nullable + public PackageSetting getPackageSetting(String packageName) { + synchronized (mPackages) { + packageName = resolveInternalPackageNameLPr( + packageName, PackageManager.VERSION_CODE_HIGHEST); + return mSettings.mPackages.get(packageName); + } + } + + void forEachPackage(Consumer<AndroidPackage> actionLocked) { synchronized (mLock) { int numPackages = mPackages.size(); for (int i = 0; i < numPackages; i++) { @@ -23827,13 +23321,13 @@ public class PackageManagerService extends IPackageManager.Stub } } - void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked, + void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId) { synchronized (mLock) { int numPackages = mPackages.size(); for (int i = 0; i < numPackages; i++) { - PackageParser.Package pkg = mPackages.valueAt(i); - PackageSetting setting = mSettings.getPackageLPr(pkg.packageName); + AndroidPackage pkg = mPackages.valueAt(i); + PackageSetting setting = mSettings.getPackageLPr(pkg.getPackageName()); if (setting == null || !setting.getInstalled(userId)) { continue; } @@ -23850,7 +23344,7 @@ public class PackageManagerService extends IPackageManager.Stub * Return a <b>copy</b> of the collection of packages known to the package manager. * @return A copy of the values of mPackages. */ - Collection<PackageParser.Package> getPackages() { + Collection<AndroidPackage> getPackages() { synchronized (mLock) { return new ArrayList<>(mPackages.values()); } @@ -23886,8 +23380,8 @@ public class PackageManagerService extends IPackageManager.Stub return mCompilerStats.getPackageStats(pkgName); } - public CompilerStats.PackageStats getOrCreateCompilerPackageStats(PackageParser.Package pkg) { - return getOrCreateCompilerPackageStats(pkg.packageName); + public CompilerStats.PackageStats getOrCreateCompilerPackageStats(AndroidPackage pkg) { + return getOrCreateCompilerPackageStats(pkg.getPackageName()); } public CompilerStats.PackageStats getOrCreateCompilerPackageStats(String pkgName) { @@ -23997,7 +23491,7 @@ public class PackageManagerService extends IPackageManager.Stub boolean canHaveOatDir(String packageName) { synchronized (mLock) { - PackageParser.Package p = mPackages.get(packageName); + AndroidPackage p = mPackages.get(packageName); if (p == null) { return false; } @@ -24005,11 +23499,11 @@ public class PackageManagerService extends IPackageManager.Stub } } - private String getOatDir(PackageParser.Package pkg) { + private String getOatDir(AndroidPackage pkg) { if (!pkg.canHaveOatDir()) { return null; } - File codePath = new File(pkg.codePath); + File codePath = new File(pkg.getCodePath()); if (codePath.isDirectory()) { return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath(); } @@ -24020,11 +23514,12 @@ public class PackageManagerService extends IPackageManager.Stub final String[] instructionSets; final List<String> codePaths; final String oatDir; - final PackageParser.Package pkg; + final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); } - instructionSets = getAppDexInstructionSets(pkg.applicationInfo); + instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), + pkg.getSecondaryCpuAbi()); codePaths = pkg.getAllCodePaths(); oatDir = getOatDir(pkg); @@ -24043,19 +23538,19 @@ public class PackageManagerService extends IPackageManager.Stub Set<String> unusedPackages = new HashSet<>(); long currentTimeInMillis = System.currentTimeMillis(); synchronized (mLock) { - for (PackageParser.Package pkg : mPackages.values()) { - PackageSetting ps = mSettings.mPackages.get(pkg.packageName); + for (AndroidPackage pkg : mPackages.values()) { + PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName()); if (ps == null) { continue; } PackageDexUsage.PackageUseInfo packageUseInfo = - getDexManager().getPackageUseInfoOrDefault(pkg.packageName); + getDexManager().getPackageUseInfoOrDefault(pkg.getPackageName()); if (PackageManagerServiceUtils .isUnusedSinceTimeInMillis(ps.firstInstallTime, currentTimeInMillis, downgradeTimeThresholdMillis, packageUseInfo, pkg.getLatestPackageUseTimeInMills(), pkg.getLatestForegroundPackageUseTimeInMills())) { - unusedPackages.add(pkg.packageName); + unusedPackages.add(pkg.getPackageName()); } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index ef47410ded8c..ded9a9c58c5e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -35,10 +35,13 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.ResolveInfo; import android.content.pm.Signature; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ApkParseUtils; import android.os.Build; import android.os.Debug; import android.os.Environment; @@ -120,7 +123,7 @@ public class PackageManagerServiceUtils { // Sort a list of apps by their last usage, most recently used apps first. The order of // packages without usage data is undefined (but they will be sorted after the packages // that do have usage data). - public static void sortPackagesByUsageDate(List<PackageParser.Package> pkgs, + public static void sortPackagesByUsageDate(List<AndroidPackage> pkgs, PackageManagerService packageManagerService) { if (!packageManagerService.isHistoricalPackageUsageAvailable()) { return; @@ -135,12 +138,12 @@ public class PackageManagerServiceUtils { // package will be removed from {@code packages} and added to {@code result} with its // dependencies. If usage data is available, the positive packages will be sorted by usage // data (with {@code sortTemp} as temporary storage). - private static void applyPackageFilter(Predicate<PackageParser.Package> filter, - Collection<PackageParser.Package> result, - Collection<PackageParser.Package> packages, - @NonNull List<PackageParser.Package> sortTemp, + private static void applyPackageFilter(Predicate<AndroidPackage> filter, + Collection<AndroidPackage> result, + Collection<AndroidPackage> packages, + @NonNull List<AndroidPackage> sortTemp, PackageManagerService packageManagerService) { - for (PackageParser.Package pkg : packages) { + for (AndroidPackage pkg : packages) { if (filter.test(pkg)) { sortTemp.add(pkg); } @@ -149,10 +152,10 @@ public class PackageManagerServiceUtils { sortPackagesByUsageDate(sortTemp, packageManagerService); packages.removeAll(sortTemp); - for (PackageParser.Package pkg : sortTemp) { + for (AndroidPackage pkg : sortTemp) { result.add(pkg); - Collection<PackageParser.Package> deps = + Collection<AndroidPackage> deps = packageManagerService.findSharedNonSystemLibraries(pkg); if (!deps.isEmpty()) { deps.removeAll(result); @@ -166,50 +169,51 @@ public class PackageManagerServiceUtils { // Sort apps by importance for dexopt ordering. Important apps are given // more priority in case the device runs out of space. - public static List<PackageParser.Package> getPackagesForDexopt( - Collection<PackageParser.Package> packages, + public static List<AndroidPackage> getPackagesForDexopt( + Collection<AndroidPackage> packages, PackageManagerService packageManagerService) { return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT); } - public static List<PackageParser.Package> getPackagesForDexopt( - Collection<PackageParser.Package> packages, + public static List<AndroidPackage> getPackagesForDexopt( + Collection<AndroidPackage> packages, PackageManagerService packageManagerService, boolean debug) { - ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages); - LinkedList<PackageParser.Package> result = new LinkedList<>(); - ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size()); + ArrayList<AndroidPackage> remainingPkgs = new ArrayList<>(packages); + LinkedList<AndroidPackage> result = new LinkedList<>(); + ArrayList<AndroidPackage> sortTemp = new ArrayList<>(remainingPkgs.size()); // Give priority to core apps. - applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp, + applyPackageFilter((pkg) -> pkg.isCoreApp(), result, remainingPkgs, sortTemp, packageManagerService); // Give priority to system apps that listen for pre boot complete. Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM); - applyPackageFilter((pkg) -> pkgNames.contains(pkg.packageName), result, remainingPkgs, + applyPackageFilter((pkg) -> pkgNames.contains(pkg.getPackageName()), result, remainingPkgs, sortTemp, packageManagerService); // Give priority to apps used by other apps. DexManager dexManager = packageManagerService.getDexManager(); applyPackageFilter((pkg) -> - dexManager.getPackageUseInfoOrDefault(pkg.packageName) + dexManager.getPackageUseInfoOrDefault(pkg.getPackageName()) .isAnyCodePathUsedByOtherApps(), result, remainingPkgs, sortTemp, packageManagerService); // Filter out packages that aren't recently used, add all remaining apps. // TODO: add a property to control this? - Predicate<PackageParser.Package> remainingPredicate; + Predicate<AndroidPackage> remainingPredicate; if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) { if (debug) { Log.i(TAG, "Looking at historical package use"); } // Get the package that was used last. - PackageParser.Package lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) -> + AndroidPackage lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) -> Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(), pkg2.getLatestForegroundPackageUseTimeInMills())); if (debug) { - Log.i(TAG, "Taking package " + lastUsed.packageName + " as reference in time use"); + Log.i(TAG, "Taking package " + lastUsed.getPackageName() + + " as reference in time use"); } long estimatedPreviousSystemUseTime = lastUsed.getLatestForegroundPackageUseTimeInMills(); @@ -285,13 +289,13 @@ public class PackageManagerServiceUtils { } } - public static String packagesToString(Collection<PackageParser.Package> c) { + public static String packagesToString(Collection<AndroidPackage> c) { StringBuilder sb = new StringBuilder(); - for (PackageParser.Package pkg : c) { + for (AndroidPackage pkg : c) { if (sb.length() > 0) { sb.append(", "); } - sb.append(pkg.packageName); + sb.append(pkg.getPackageName()); } return sb.toString(); } @@ -309,16 +313,16 @@ public class PackageManagerServiceUtils { return false; } - public static long getLastModifiedTime(PackageParser.Package pkg) { - final File srcFile = new File(pkg.codePath); + public static long getLastModifiedTime(AndroidPackage pkg) { + final File srcFile = new File(pkg.getCodePath()); if (!srcFile.isDirectory()) { return srcFile.lastModified(); } - final File baseFile = new File(pkg.baseCodePath); + final File baseFile = new File(pkg.getBaseCodePath()); long maxModifiedTime = baseFile.lastModified(); - if (pkg.splitCodePaths != null) { - for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) { - final File splitFile = new File(pkg.splitCodePaths[i]); + if (pkg.getSplitCodePaths() != null) { + for (int i = pkg.getSplitCodePaths().length - 1; i >=0; --i) { + final File splitFile = new File(pkg.getSplitCodePaths()[i]); maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified()); } } @@ -539,7 +543,7 @@ public class PackageManagerServiceUtils { private static boolean matchSignatureInSystem(PackageSetting pkgSetting, PackageSetting disabledPkgSetting) { try { - PackageParser.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */); + ApkParseUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */); if (pkgSetting.signatures.mSigningDetails.checkCapability( disabledPkgSetting.signatures.mSigningDetails, PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA) @@ -905,8 +909,10 @@ public class PackageManagerServiceUtils { * Returns the {@link PermissionsState} for the given package. If the {@link PermissionsState} * could not be found, {@code null} will be returned. */ - public static PermissionsState getPermissionsState(PackageParser.Package pkg) { - final PackageSetting packageSetting = (PackageSetting) pkg.mExtras; + public static PermissionsState getPermissionsState( + PackageManagerInternal packageManagerInternal, AndroidPackage pkg) { + final PackageSetting packageSetting = + (PackageSetting) packageManagerInternal.getPackageSetting(pkg.getPackageName()); if (packageSetting == null) { return null; } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index b96109683115..fff404f3ede6 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -48,7 +48,6 @@ import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; -import android.content.pm.PackageParser; import android.content.pm.PackageParser.ApkLite; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; @@ -62,6 +61,7 @@ import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.ISnapshotRuntimeProfileCallback; +import android.content.pm.parsing.ApkLiteParseUtils; import android.content.res.AssetManager; import android.content.res.Resources; import android.content.rollback.IRollbackManager; @@ -453,7 +453,7 @@ class PackageManagerShellCommand extends ShellCommand { throw new IllegalArgumentException("Error: Can't open file: " + inPath); } try { - ApkLite baseApk = PackageParser.parseApkLite(fd.getFileDescriptor(), inPath, 0); + ApkLite baseApk = ApkLiteParseUtils.parseApkLite(fd.getFileDescriptor(), inPath, 0); PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null, null, null); sessionSize += PackageHelper.calculateInstalledSize(pkgLite, diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index d38dd9344821..bbc0dc986b0c 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -18,8 +18,9 @@ package com.android.server.pm; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; import android.content.pm.UserInfo; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsedPackage; import android.service.pm.PackageProto; import android.util.proto.ProtoOutputStream; @@ -31,9 +32,11 @@ import java.util.List; /** * Settings data for a particular package we know about. */ -public final class PackageSetting extends PackageSettingBase { +public final class PackageSetting extends PackageSettingBase implements + ParsedPackage.PackageSettingCallback { int appId; - PackageParser.Package pkg; + + public AndroidPackage pkg; /** * WARNING. The object reference is important. We perform integer equality and NOT * object equality to check whether shared user settings are the same. @@ -50,12 +53,12 @@ public final class PackageSetting extends PackageSettingBase { PackageSetting(String name, String realName, File codePath, File resourcePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, - long pVersionCode, int pkgFlags, int privateFlags, String parentPackageName, - List<String> childPackageNames, int sharedUserId, String[] usesStaticLibraries, + long pVersionCode, int pkgFlags, int privateFlags, + int sharedUserId, String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) { super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, - pVersionCode, pkgFlags, privateFlags, parentPackageName, childPackageNames, + pVersionCode, pkgFlags, privateFlags, usesStaticLibraries, usesStaticLibrariesVersions); this.sharedUserId = sharedUserId; } @@ -116,10 +119,6 @@ public final class PackageSetting extends PackageSettingBase { : super.getPermissionsState(); } - public PackageParser.Package getPackage() { - return pkg; - } - public int getAppId() { return appId; } @@ -132,6 +131,7 @@ public final class PackageSetting extends PackageSettingBase { return installPermissionsFixed; } + // TODO(b/135203078): Remove these in favor of reading from the package directly public boolean isPrivileged() { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; } @@ -176,10 +176,6 @@ public final class PackageSetting extends PackageSettingBase { return true; } - public boolean hasChildPackages() { - return childPackageNames != null && !childPackageNames.isEmpty(); - } - public void dumpDebug(ProtoOutputStream proto, long fieldId, List<UserInfo> users) { final long packageToken = proto.start(fieldId); proto.write(PackageProto.NAME, (realName != null ? realName : name)); @@ -190,18 +186,19 @@ public final class PackageSetting extends PackageSettingBase { proto.write(PackageProto.INSTALLER_NAME, installSource.installerPackageName); if (pkg != null) { - proto.write(PackageProto.VERSION_STRING, pkg.mVersionName); + proto.write(PackageProto.VERSION_STRING, pkg.getVersionName()); long splitToken = proto.start(PackageProto.SPLITS); proto.write(PackageProto.SplitProto.NAME, "base"); - proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.baseRevisionCode); + proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.getBaseRevisionCode()); proto.end(splitToken); - if (pkg.splitNames != null) { - for (int i = 0; i < pkg.splitNames.length; i++) { + if (pkg.getSplitNames() != null) { + for (int i = 0; i < pkg.getSplitNames().length; i++) { splitToken = proto.start(PackageProto.SPLITS); - proto.write(PackageProto.SplitProto.NAME, pkg.splitNames[i]); - proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.splitRevisionCodes[i]); + proto.write(PackageProto.SplitProto.NAME, pkg.getSplitNames()[i]); + proto.write(PackageProto.SplitProto.REVISION_CODE, + pkg.getSplitRevisionCodes()[i]); proto.end(splitToken); } } @@ -225,4 +222,10 @@ public final class PackageSetting extends PackageSettingBase { sharedUserId = other.sharedUserId; sharedUser = other.sharedUser; } + + // TODO(b/135203078): Move to constructor + @Override + public void setAndroidPackage(AndroidPackage pkg) { + this.pkg = pkg; + } } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 45ab3575c805..671450d71b4d 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -39,7 +39,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.io.File; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; @@ -54,9 +53,6 @@ public abstract class PackageSettingBase extends SettingBase { public final String name; final String realName; - String parentPackageName; - List<String> childPackageNames; - /** * Path where this package was found on disk. For monolithic packages * this is path to single base APK file; for cluster packages this is @@ -138,14 +134,10 @@ public abstract class PackageSettingBase extends SettingBase { String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, long pVersionCode, int pkgFlags, int pkgPrivateFlags, - String parentPackageName, List<String> childPackageNames, String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) { super(pkgFlags, pkgPrivateFlags); this.name = name; this.realName = realName; - this.parentPackageName = parentPackageName; - this.childPackageNames = (childPackageNames != null) - ? new ArrayList<>(childPackageNames) : null; this.usesStaticLibraries = usesStaticLibraries; this.usesStaticLibrariesVersions = usesStaticLibrariesVersions; this.codePath = codePath; @@ -235,8 +227,6 @@ public abstract class PackageSettingBase extends SettingBase { } private void doCopy(PackageSettingBase orig) { - childPackageNames = (orig.childPackageNames != null) - ? new ArrayList<>(orig.childPackageNames) : null; codePath = orig.codePath; codePathString = orig.codePathString; cpuAbiOverrideString = orig.cpuAbiOverrideString; @@ -247,7 +237,6 @@ public abstract class PackageSettingBase extends SettingBase { lastUpdateTime = orig.lastUpdateTime; legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString; // Intentionally skip mOldCodePaths; it's not relevant for copies - parentPackageName = orig.parentPackageName; primaryCpuAbiString = orig.primaryCpuAbiString; resourcePath = orig.resourcePath; resourcePathString = orig.resourcePathString; @@ -670,8 +659,6 @@ public abstract class PackageSettingBase extends SettingBase { protected PackageSettingBase updateFrom(PackageSettingBase other) { super.copyFrom(other); - this.parentPackageName = other.parentPackageName; - this.childPackageNames = other.childPackageNames; this.codePath = other.codePath; this.codePathString = other.codePathString; this.resourcePath = other.resourcePath; diff --git a/services/core/java/com/android/server/pm/PackageUsage.java b/services/core/java/com/android/server/pm/PackageUsage.java index ac1f739cd9f8..ce2c9e767d5e 100644 --- a/services/core/java/com/android/server/pm/PackageUsage.java +++ b/services/core/java/com/android/server/pm/PackageUsage.java @@ -20,7 +20,7 @@ import static android.os.Process.PACKAGE_INFO_GID; import static android.os.Process.SYSTEM_UID; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.os.FileUtils; import android.util.AtomicFile; import android.util.Log; @@ -36,7 +36,7 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Map; -class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> { +class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> { private static final String USAGE_FILE_MAGIC = "PACKAGE_USAGE__VERSION_"; private static final String USAGE_FILE_MAGIC_VERSION_1 = USAGE_FILE_MAGIC + "1"; @@ -52,7 +52,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> } @Override - protected void writeInternal(Map<String, PackageParser.Package> packages) { + protected void writeInternal(Map<String, AndroidPackage> packages) { AtomicFile file = getFile(); FileOutputStream f = null; try { @@ -66,13 +66,13 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> sb.append('\n'); out.write(sb.toString().getBytes(StandardCharsets.US_ASCII)); - for (PackageParser.Package pkg : packages.values()) { + for (AndroidPackage pkg : packages.values()) { if (pkg.getLatestPackageUseTimeInMills() == 0L) { continue; } sb.setLength(0); - sb.append(pkg.packageName); - for (long usageTimeInMillis : pkg.mLastPackageUsageTimeInMills) { + sb.append(pkg.getPackageName()); + for (long usageTimeInMillis : pkg.getLastPackageUsageTimeInMills()) { sb.append(' '); sb.append(usageTimeInMillis); } @@ -90,7 +90,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> } @Override - protected void readInternal(Map<String, PackageParser.Package> packages) { + protected void readInternal(Map<String, AndroidPackage> packages) { AtomicFile file = getFile(); BufferedInputStream in = null; try { @@ -114,7 +114,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> } } - private void readVersion0LP(Map<String, PackageParser.Package> packages, InputStream in, + private void readVersion0LP(Map<String, AndroidPackage> packages, InputStream in, StringBuffer sb, String firstLine) throws IOException { // Initial version of the file had no version number and stored one @@ -128,7 +128,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> } String packageName = tokens[0]; - PackageParser.Package pkg = packages.get(packageName); + AndroidPackage pkg = packages.get(packageName); if (pkg == null) { continue; } @@ -137,12 +137,12 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> for (int reason = 0; reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT; reason++) { - pkg.mLastPackageUsageTimeInMills[reason] = timestamp; + pkg.mutate().setLastPackageUsageTimeInMills(reason, timestamp); } } } - private void readVersion1LP(Map<String, PackageParser.Package> packages, InputStream in, + private void readVersion1LP(Map<String, AndroidPackage> packages, InputStream in, StringBuffer sb) throws IOException { // Version 1 of the file started with the corresponding version // number and then stored a package name and eight timestamps per line. @@ -154,7 +154,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> } String packageName = tokens[0]; - PackageParser.Package pkg = packages.get(packageName); + AndroidPackage pkg = packages.get(packageName); if (pkg == null) { continue; } @@ -162,7 +162,8 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> for (int reason = 0; reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT; reason++) { - pkg.mLastPackageUsageTimeInMills[reason] = parseAsLong(tokens[reason + 1]); + pkg.mutate().setLastPackageUsageTimeInMills(reason, + parseAsLong(tokens[reason + 1])); } } } @@ -196,4 +197,4 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> sb.append((char)ch); } } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java index 4ff3e1218b53..a5065145cafd 100644 --- a/services/core/java/com/android/server/pm/ParallelPackageParser.java +++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java @@ -16,7 +16,10 @@ package com.android.server.pm; +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; + import android.content.pm.PackageParser; +import android.content.pm.parsing.ParsedPackage; import android.os.Process; import android.os.Trace; import android.util.DisplayMetrics; @@ -30,8 +33,6 @@ import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; -import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; - /** * Helper class for parallel parsing of packages using {@link PackageParser}. * <p>Parsing requests are processed by a thread-pool of {@link #MAX_THREADS}. @@ -65,14 +66,14 @@ class ParallelPackageParser implements AutoCloseable { static class ParseResult { - PackageParser.Package pkg; // Parsed package + ParsedPackage parsedPackage; // Parsed package File scanFile; // File that was parsed Throwable throwable; // Set if an error occurs during parsing @Override public String toString() { return "ParseResult{" + - "pkg=" + pkg + + "parsedPackage=" + parsedPackage + ", scanFile=" + scanFile + ", throwable=" + throwable + '}'; @@ -100,7 +101,7 @@ class ParallelPackageParser implements AutoCloseable { /** * Submits the file for parsing * @param scanFile file to scan - * @param parseFlags parse falgs + * @param parseFlags parse flags */ public void submit(File scanFile, int parseFlags) { mService.submit(() -> { @@ -114,7 +115,7 @@ class ParallelPackageParser implements AutoCloseable { pp.setCacheDir(mCacheDir); pp.setCallback(mPackageParserCallback); pr.scanFile = scanFile; - pr.pkg = parsePackage(pp, scanFile, parseFlags); + pr.parsedPackage = parsePackage(pp, scanFile, parseFlags); } catch (Throwable e) { pr.throwable = e; } finally { @@ -133,9 +134,9 @@ class ParallelPackageParser implements AutoCloseable { } @VisibleForTesting - protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile, + protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile, int parseFlags) throws PackageParser.PackageParserException { - return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */); + return packageParser.parseParsedPackage(scanFile, parseFlags, true); } @Override diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java index d20f20ffec46..466f19c43289 100644 --- a/services/core/java/com/android/server/pm/SELinuxMMAC.java +++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java @@ -21,6 +21,7 @@ import android.compat.annotation.EnabledAfter; import android.content.pm.PackageParser; import android.content.pm.PackageParser.SigningDetails; import android.content.pm.Signature; +import android.content.pm.parsing.AndroidPackage; import android.os.Environment; import android.util.Slog; import android.util.Xml; @@ -336,7 +337,7 @@ public final class SELinuxMMAC { } } - private static int getTargetSdkVersionForSeInfo(PackageParser.Package pkg, + private static int getTargetSdkVersionForSeInfo(AndroidPackage pkg, SharedUserSetting sharedUserSetting, PlatformCompat compatibility) { // Apps which share a sharedUserId must be placed in the same selinux domain. If this // package is the first app installed as this shared user, set seInfoTargetSdkVersion to its @@ -349,11 +350,11 @@ public final class SELinuxMMAC { if ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) { return sharedUserSetting.seInfoTargetSdkVersion; } - if (compatibility.isChangeEnabled(SELINUX_LATEST_CHANGES, pkg.applicationInfo)) { + if (compatibility.isChangeEnabled(SELINUX_LATEST_CHANGES, pkg.toAppInfoWithoutState())) { return android.os.Build.VERSION_CODES.R; } - return pkg.applicationInfo.targetSdkVersion; + return pkg.getTargetSdkVersion(); } /** @@ -367,7 +368,7 @@ public final class SELinuxMMAC { * @param compatibility the PlatformCompat service to ask about state of compat changes. * @return String representing the resulting seinfo. */ - public static String getSeInfo(PackageParser.Package pkg, SharedUserSetting sharedUserSetting, + public static String getSeInfo(AndroidPackage pkg, SharedUserSetting sharedUserSetting, PlatformCompat compatibility) { final int targetSdkVersion = getTargetSdkVersionForSeInfo(pkg, sharedUserSetting, compatibility); @@ -391,7 +392,7 @@ public final class SELinuxMMAC { * MINIMUM_TARGETSDKVERSION. * @return String representing the resulting seinfo. */ - public static String getSeInfo(PackageParser.Package pkg, boolean isPrivileged, + public static String getSeInfo(AndroidPackage pkg, boolean isPrivileged, int targetSdkVersion) { String seInfo = null; synchronized (sPolicies) { @@ -420,8 +421,8 @@ public final class SELinuxMMAC { seInfo += TARGETSDKVERSION_STR + targetSdkVersion; if (DEBUG_POLICY_INSTALL) { - Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " + - "seinfo=" + seInfo); + Slog.i(TAG, "package (" + pkg.getPackageName() + ") labeled with " + + "seinfo=" + seInfo); } return seInfo; } @@ -430,7 +431,7 @@ public final class SELinuxMMAC { /** * Holds valid policy representations of individual stanzas from a mac_permissions.xml * file. Each instance can further be used to assign seinfo values to apks using the - * {@link Policy#getMatchedSeinfo} method. To create an instance of this use the + * {@link Policy#getMatchedSeInfo(AndroidPackage)} method. To create an instance of this use the * {@link PolicyBuilder} pattern class, where each instance is validated against a set * of invariants before being built and returned. Each instance can be guaranteed to * hold one valid policy stanza as outlined in the system/sepolicy/mac_permissions.xml @@ -557,21 +558,21 @@ final class Policy { * @return A string representing the seinfo matched during policy lookup. * A value of null can also be returned if no match occured. */ - public String getMatchedSeInfo(PackageParser.Package pkg) { + public String getMatchedSeInfo(AndroidPackage pkg) { // Check for exact signature matches across all certs. Signature[] certs = mCerts.toArray(new Signature[0]); - if (pkg.mSigningDetails != SigningDetails.UNKNOWN - && !Signature.areExactMatch(certs, pkg.mSigningDetails.signatures)) { + if (pkg.getSigningDetails() != SigningDetails.UNKNOWN + && !Signature.areExactMatch(certs, pkg.getSigningDetails().signatures)) { // certs aren't exact match, but the package may have rotated from the known system cert - if (certs.length > 1 || !pkg.mSigningDetails.hasCertificate(certs[0])) { + if (certs.length > 1 || !pkg.getSigningDetails().hasCertificate(certs[0])) { return null; } } // Check for inner package name matches given that the // signature checks already passed. - String seinfoValue = mPkgMap.get(pkg.packageName); + String seinfoValue = mPkgMap.get(pkg.getPackageName()); if (seinfoValue != null) { return seinfoValue; } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 1082eaa0374e..6653011b8b22 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -42,7 +42,6 @@ import android.content.pm.ComponentInfo; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; -import android.content.pm.PackageParser; import android.content.pm.PackageUserState; import android.content.pm.PermissionInfo; import android.content.pm.ResolveInfo; @@ -50,6 +49,10 @@ import android.content.pm.Signature; import android.content.pm.SuspendDialogInfo; import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -479,8 +482,8 @@ public final class Settings { final PackageSetting dp = mDisabledSysPackages.get(name); // always make sure the system package code and resource paths dont change if (dp == null && p.pkg != null && p.pkg.isSystem() && !p.pkg.isUpdatedSystemApp()) { - if((p.pkg != null) && (p.pkg.applicationInfo != null)) { - p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + if(p.pkg != null) { + p.pkg.mutate().setUpdatedSystemApp(true); } final PackageSetting disabled; if (replaced) { @@ -506,14 +509,14 @@ public final class Settings { return null; } // Reset flag in ApplicationInfo object - if((p.pkg != null) && (p.pkg.applicationInfo != null)) { - p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + if(p.pkg != null) { + p.pkg.mutate().setUpdatedSystemApp(false); } PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath, p.legacyNativeLibraryPathString, p.primaryCpuAbiString, p.secondaryCpuAbiString, p.cpuAbiOverrideString, p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags, - p.parentPackageName, p.childPackageNames, p.usesStaticLibraries, + p.usesStaticLibraries, p.usesStaticLibrariesVersions); mDisabledSysPackages.remove(name); return ret; @@ -530,8 +533,7 @@ public final class Settings { PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, long vc, int - pkgFlags, int pkgPrivateFlags, String parentPackageName, - List<String> childPackageNames, String[] usesStaticLibraries, + pkgFlags, int pkgPrivateFlags, String[] usesStaticLibraries, long[] usesStaticLibraryNames) { PackageSetting p = mPackages.get(name); if (p != null) { @@ -544,8 +546,8 @@ public final class Settings { } p = new PackageSetting(name, realName, codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, - cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, parentPackageName, - childPackageNames, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames); + cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, + 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames); p.appId = uid; if (registerExistingAppIdLPw(uid, p, name)) { mPackages.put(name, p); @@ -607,19 +609,15 @@ public final class Settings { File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi, String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags, UserHandle installUser, boolean allowInstall, boolean instantApp, - boolean virtualPreload, String parentPkgName, List<String> childPkgNames, - UserManagerService userManager, + boolean virtualPreload, UserManagerService userManager, String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) { final PackageSetting pkgSetting; if (originalPkg != null) { if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " + pkgName + " is adopting original package " + originalPkg.name); pkgSetting = new PackageSetting(originalPkg, pkgName /*realPkgName*/); - pkgSetting.childPackageNames = - (childPkgNames != null) ? new ArrayList<>(childPkgNames) : null; pkgSetting.codePath = codePath; pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath; - pkgSetting.parentPackageName = parentPkgName; pkgSetting.pkgFlags = pkgFlags; pkgSetting.pkgPrivateFlags = pkgPrivateFlags; pkgSetting.primaryCpuAbiString = primaryCpuAbi; @@ -637,7 +635,7 @@ public final class Settings { pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath, legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi, null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags, - parentPkgName, childPkgNames, 0 /*sharedUserId*/, usesStaticLibraries, + 0 /*sharedUserId*/, usesStaticLibraries, usesStaticLibrariesVersions); pkgSetting.setTimeStamp(codePath.lastModified()); pkgSetting.sharedUser = sharedUser; @@ -721,7 +719,7 @@ public final class Settings { @NonNull File codePath, File resourcePath, @Nullable String legacyNativeLibraryPath, @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi, int pkgFlags, int pkgPrivateFlags, - @Nullable List<String> childPkgNames, @NonNull UserManagerService userManager, + @NonNull UserManagerService userManager, @Nullable String[] usesStaticLibraries, @Nullable long[] usesStaticLibrariesVersions) throws PackageManagerException { final String pkgName = pkgSetting.name; @@ -799,9 +797,6 @@ public final class Settings { pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM; pkgSetting.primaryCpuAbiString = primaryCpuAbi; pkgSetting.secondaryCpuAbiString = secondaryCpuAbi; - if (childPkgNames != null) { - pkgSetting.childPackageNames = new ArrayList<>(childPkgNames); - } // Update static shared library dependencies if needed if (usesStaticLibraries != null && usesStaticLibrariesVersions != null && usesStaticLibraries.length == usesStaticLibrariesVersions.length) { @@ -870,15 +865,15 @@ public final class Settings { // TODO: Move to scanPackageOnlyLI() after verifying signatures are setup correctly // by that time. - void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) { + void insertPackageSettingLPw(PackageSetting p, AndroidPackage pkg) { // Update signatures if needed. if (p.signatures.mSigningDetails.signatures == null) { - p.signatures.mSigningDetails = pkg.mSigningDetails; + p.signatures.mSigningDetails = pkg.getSigningDetails(); } // If this app defines a shared user id initialize // the shared user signatures as well. if (p.sharedUser != null && p.sharedUser.signatures.mSigningDetails.signatures == null) { - p.sharedUser.signatures.mSigningDetails = pkg.mSigningDetails; + p.sharedUser.signatures.mSigningDetails = pkg.getSigningDetails(); } addPackageSettingLPw(p, p.sharedUser); } @@ -955,7 +950,7 @@ public final class Settings { int affectedUserId = UserHandle.USER_NULL; // Update permissions - for (String eachPerm : deletedPs.pkg.requestedPermissions) { + for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) { BasePermission bp = mPermissions.getPermission(eachPerm); if (bp == null) { continue; @@ -965,8 +960,8 @@ public final class Settings { boolean used = false; for (PackageSetting pkg : sus.packages) { if (pkg.pkg != null - && !pkg.pkg.packageName.equals(deletedPs.pkg.packageName) - && pkg.pkg.requestedPermissions.contains(eachPerm)) { + && !pkg.pkg.getPackageName().equals(deletedPs.pkg.getPackageName()) + && pkg.pkg.getRequestedPermissions().contains(eachPerm)) { used = true; break; } @@ -976,13 +971,13 @@ public final class Settings { } PermissionsState permissionsState = sus.getPermissionsState(); - PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.packageName); + PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.getPackageName()); // If the package is shadowing is a disabled system package, // do not drop permissions that the shadowed package requests. if (disabledPs != null) { boolean reqByDisabledSysPkg = false; - for (String permission : disabledPs.pkg.requestedPermissions) { + for (String permission : disabledPs.pkg.getRequestedPermissions()) { if (permission.equals(eachPerm)) { reqByDisabledSysPkg = true; break; @@ -2215,20 +2210,6 @@ public final class Settings { serializer.endTag(null, TAG_PERMISSIONS); } - void writeChildPackagesLPw(XmlSerializer serializer, List<String> childPackageNames) - throws IOException { - if (childPackageNames == null) { - return; - } - final int childCount = childPackageNames.size(); - for (int i = 0; i < childCount; i++) { - String childPackageName = childPackageNames.get(i); - serializer.startTag(null, TAG_CHILD_PACKAGE); - serializer.attribute(null, ATTR_NAME, childPackageName); - serializer.endTag(null, TAG_CHILD_PACKAGE); - } - } - void readUsesStaticLibLPw(XmlPullParser parser, PackageSetting outPs) throws IOException, XmlPullParserException { int outerDepth = parser.getDepth(); @@ -2682,17 +2663,15 @@ public final class Settings { StringBuilder sb = new StringBuilder(); for (final PackageSetting pkg : mPackages.values()) { - if (pkg.pkg == null || pkg.pkg.applicationInfo == null - || pkg.pkg.applicationInfo.dataDir == null) { + if (pkg.pkg == null || pkg.pkg.getDataDir() == null) { if (!"android".equals(pkg.name)) { Slog.w(TAG, "Skipping " + pkg + " due to missing metadata"); } continue; } - final ApplicationInfo ai = pkg.pkg.applicationInfo; - final String dataPath = ai.dataDir; - final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + final String dataPath = pkg.pkg.getDataDir(); + final boolean isDebug = (pkg.pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0; final int[] gids = pkg.getPermissionsState().computeGids(userIds); // Avoid any application that has a space in its path. @@ -2717,13 +2696,13 @@ public final class Settings { // system/core/libpackagelistparser // sb.setLength(0); - sb.append(ai.packageName); + sb.append(pkg.pkg.getPackageName()); sb.append(" "); - sb.append(ai.uid); + sb.append(pkg.pkg.getUid()); sb.append(isDebug ? " 1 " : " 0 "); sb.append(dataPath); sb.append(" "); - sb.append(ai.seInfo); + sb.append(pkg.pkg.getSeInfo()); sb.append(" "); if (gids != null && gids.length > 0) { sb.append(gids[0]); @@ -2735,9 +2714,9 @@ public final class Settings { sb.append("none"); } sb.append(" "); - sb.append(ai.isProfileableByShell() ? "1" : "0"); + sb.append(pkg.pkg.isProfileableByShell() ? "1" : "0"); sb.append(" "); - sb.append(String.valueOf(ai.longVersionCode)); + sb.append(pkg.pkg.getLongVersionCode()); sb.append("\n"); writer.append(sb); } @@ -2786,12 +2765,6 @@ public final class Settings { serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId)); } - if (pkg.parentPackageName != null) { - serializer.attribute(null, "parentPackageName", pkg.parentPackageName); - } - - writeChildPackagesLPw(serializer, pkg.childPackageNames); - writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions); // If this is a shared user, the permissions will be written there. @@ -2861,15 +2834,10 @@ public final class Settings { if (pkg.categoryHint != ApplicationInfo.CATEGORY_UNDEFINED) { serializer.attribute(null, "categoryHint", Integer.toString(pkg.categoryHint)); } - if (pkg.parentPackageName != null) { - serializer.attribute(null, "parentPackageName", pkg.parentPackageName); - } if (pkg.updateAvailable) { serializer.attribute(null, "updateAvailable", "true"); } - writeChildPackagesLPw(serializer, pkg.childPackageNames); - writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions); pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); @@ -3161,13 +3129,13 @@ public final class Settings { LocalServices.getService(PackageManagerInternal.class); for (PackageSetting ps : mPackages.values()) { if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null - && ps.pkg.preferredActivityFilters != null) { - ArrayList<PackageParser.ActivityIntentInfo> intents - = ps.pkg.preferredActivityFilters; + && ps.pkg.getPreferredActivityFilters() != null) { + List<ComponentParseUtils.ParsedActivityIntentInfo> intents + = ps.pkg.getPreferredActivityFilters(); for (int i=0; i<intents.size(); i++) { - PackageParser.ActivityIntentInfo aii = intents.get(i); + ComponentParseUtils.ParsedActivityIntentInfo aii = intents.get(i); applyDefaultPreferredActivityLPw(pmInternal, aii, new ComponentName( - ps.name, aii.activity.className), userId); + ps.name, aii.getClassName()), userId); } } } @@ -3527,7 +3495,7 @@ public final class Settings { PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr, secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags, - parentPackageName, null /*childPackageNames*/, 0 /*sharedUserId*/, null, null); + 0 /*sharedUserId*/, null, null); String timeStampStr = parser.getAttributeValue(null, "ft"); if (timeStampStr != null) { try { @@ -3576,12 +3544,6 @@ public final class Settings { if (parser.getName().equals(TAG_PERMISSIONS)) { readInstallPermissionsLPr(parser, ps.getPermissionsState()); - } else if (parser.getName().equals(TAG_CHILD_PACKAGE)) { - String childPackageName = parser.getAttributeValue(null, ATTR_NAME); - if (ps.childPackageNames == null) { - ps.childPackageNames = new ArrayList<>(); - } - ps.childPackageNames.add(childPackageName); } else if (parser.getName().equals(TAG_USES_STATIC_LIB)) { readUsesStaticLibLPw(parser, ps); } else { @@ -3628,7 +3590,6 @@ public final class Settings { PackageSetting packageSetting = null; String version = null; long versionCode = 0; - String parentPackageName; try { name = parser.getAttributeValue(null, ATTR_NAME); realName = parser.getAttributeValue(null, "realName"); @@ -3640,8 +3601,6 @@ public final class Settings { legacyCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi"); - parentPackageName = parser.getAttributeValue(null, "parentPackageName"); - legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); primaryCpuAbiString = parser.getAttributeValue(null, "primaryCpuAbi"); secondaryCpuAbiString = parser.getAttributeValue(null, "secondaryCpuAbi"); @@ -3770,7 +3729,7 @@ public final class Settings { packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags, - pkgPrivateFlags, parentPackageName, null /*childPackageNames*/, + pkgPrivateFlags, null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/); if (PackageManagerService.DEBUG_SETTINGS) Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId=" @@ -3789,8 +3748,8 @@ public final class Settings { packageSetting = new PackageSetting(name.intern(), realName, new File( codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, - versionCode, pkgFlags, pkgPrivateFlags, parentPackageName, - null /*childPackageNames*/, sharedUserId, + versionCode, pkgFlags, pkgPrivateFlags, + sharedUserId, null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/); packageSetting.setTimeStamp(timeStamp); packageSetting.firstInstallTime = firstInstallTime; @@ -3899,12 +3858,6 @@ public final class Settings { packageSetting.keySetData.addDefinedKeySet(id, alias); } else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) { readDomainVerificationLPw(parser, packageSetting); - } else if (tagName.equals(TAG_CHILD_PACKAGE)) { - String childPackageName = parser.getAttributeValue(null, ATTR_NAME); - if (packageSetting.childPackageNames == null) { - packageSetting.childPackageNames = new ArrayList<>(); - } - packageSetting.childPackageNames.add(childPackageName); } else { PackageManagerService.reportSettingsProblem(Log.WARN, "Unknown element under <package>: " + parser.getName()); @@ -4057,13 +4010,13 @@ public final class Settings { Iterator<PackageSetting> packagesIterator = packages.iterator(); for (int i = 0; i < packagesCount; i++) { PackageSetting ps = packagesIterator.next(); - if (ps.pkg == null || ps.pkg.applicationInfo == null) { + if (ps.pkg == null) { continue; } final boolean shouldInstall = ps.isSystem() && (skipPackageWhitelist || installablePackages.contains(ps.name)) && !ArrayUtils.contains(disallowedPackages, ps.name) && - !ps.pkg.applicationInfo.hiddenUntilInstalled; + !ps.pkg.isHiddenUntilInstalled(); // Only system apps are initially installed. ps.setInstalled(shouldInstall, userHandle); if (!shouldInstall) { @@ -4074,8 +4027,8 @@ public final class Settings { volumeUuids[i] = ps.volumeUuid; names[i] = ps.name; appIds[i] = ps.appId; - seinfos[i] = ps.pkg.applicationInfo.seInfo; - targetSdkVersions[i] = ps.pkg.applicationInfo.targetSdkVersion; + seinfos[i] = ps.pkg.getSeInfo(); + targetSdkVersions[i] = ps.pkg.getTargetSdkVersion(); } } t.traceBegin("createAppData"); @@ -4185,28 +4138,6 @@ public final class Settings { return mVerifierDeviceIdentity; } - boolean hasOtherDisabledSystemPkgWithChildLPr(String parentPackageName, - String childPackageName) { - final int packageCount = mDisabledSysPackages.size(); - for (int i = 0; i < packageCount; i++) { - PackageSetting disabledPs = mDisabledSysPackages.valueAt(i); - if (disabledPs.childPackageNames == null || disabledPs.childPackageNames.isEmpty()) { - continue; - } - if (disabledPs.name.equals(parentPackageName)) { - continue; - } - final int childCount = disabledPs.childPackageNames.size(); - for (int j = 0; j < childCount; j++) { - String currChildPackageName = disabledPs.childPackageNames.get(j); - if (currChildPackageName.equals(childPackageName)) { - return true; - } - } - } - return false; - } - /** * Returns the disabled {@link PackageSetting} for the provided package name if one exists, * {@code null} otherwise. @@ -4229,26 +4160,6 @@ public final class Settings { return getDisabledSystemPkgLPr(enabledPackageSetting.name); } - /** - * Fetches an array of the child {@link PackageSetting}s for all child package names referenced - * by the provided parent {@link PackageSetting} or {@code null} if no children are referenced. - * - * Note: Any child packages not found will be null in the returned array. - */ - @Nullable - public PackageSetting[] getChildSettingsLPr(PackageSetting parentPackageSetting) { - if (parentPackageSetting == null || !parentPackageSetting.hasChildPackages()) { - return null; - } - final int childCount = parentPackageSetting.childPackageNames.size(); - PackageSetting[] children = - new PackageSetting[childCount]; - for (int i = 0; i < childCount; i++) { - children[i] = mPackages.get(parentPackageSetting.childPackageNames.get(i)); - } - return children; - } - boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) { final PackageSetting ps = mPackages.get(componentInfo.packageName); if (ps == null) return false; @@ -4257,6 +4168,15 @@ public final class Settings { return userState.isMatch(componentInfo, flags); } + boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedComponent component, int flags, + int userId) { + final PackageSetting ps = mPackages.get(component.getPackageName()); + if (ps == null) return false; + + final PackageUserState userState = ps.readUserState(userId); + return userState.isMatch(pkg.isSystem(), pkg.isEnabled(), component, flags); + } + boolean isOrphaned(String packageName) { final PackageSetting pkg = mPackages.get(packageName); if (pkg == null) { @@ -4467,6 +4387,7 @@ public final class Settings { void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag, ArraySet<String> permissionNames, PackageSetting ps, SimpleDateFormat sdf, Date date, List<UserInfo> users, boolean dumpAll, boolean dumpAllComponents) { + AndroidPackage pkg = ps.pkg; if (checkinTag != null) { pw.print(checkinTag); pw.print(","); @@ -4483,15 +4404,16 @@ public final class Settings { pw.print(ps.installSource.installerPackageName != null ? ps.installSource.installerPackageName : "?"); pw.println(); - if (ps.pkg != null) { + if (pkg != null) { pw.print(checkinTag); pw.print("-"); pw.print("splt,"); pw.print("base,"); - pw.println(ps.pkg.baseRevisionCode); - if (ps.pkg.splitNames != null) { - for (int i = 0; i < ps.pkg.splitNames.length; i++) { + pw.println(pkg.getBaseRevisionCode()); + if (pkg.getSplitNames() != null) { + int[] splitRevisionCodes = pkg.getSplitRevisionCodes(); + for (int i = 0; i < pkg.getSplitNames().length; i++) { pw.print(checkinTag); pw.print("-"); pw.print("splt,"); - pw.print(ps.pkg.splitNames[i]); pw.print(","); - pw.println(ps.pkg.splitRevisionCodes[i]); + pw.print(pkg.getSplitNames()[i]); pw.print(","); + pw.println(splitRevisionCodes[i]); } } } @@ -4538,7 +4460,7 @@ public final class Settings { if (ps.sharedUser != null) { pw.print(prefix); pw.print(" sharedUser="); pw.println(ps.sharedUser); } - pw.print(prefix); pw.print(" pkg="); pw.println(ps.pkg); + pw.print(prefix); pw.print(" pkg="); pw.println(pkg); pw.print(prefix); pw.print(" codePath="); pw.println(ps.codePathString); if (permissionNames == null) { pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString); @@ -4548,140 +4470,123 @@ public final class Settings { pw.print(prefix); pw.print(" secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString); } pw.print(prefix); pw.print(" versionCode="); pw.print(ps.versionCode); - if (ps.pkg != null) { - pw.print(" minSdk="); pw.print(ps.pkg.applicationInfo.minSdkVersion); - pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion); + if (pkg != null) { + pw.print(" minSdk="); pw.print(pkg.getMinSdkVersion()); + pw.print(" targetSdk="); pw.print(pkg.getTargetSdkVersion()); } pw.println(); - if (ps.pkg != null) { - if (ps.pkg.parentPackage != null) { - PackageParser.Package parentPkg = ps.pkg.parentPackage; - PackageSetting pps = mPackages.get(parentPkg.packageName); - if (pps == null || !pps.codePathString.equals(parentPkg.codePath)) { - pps = mDisabledSysPackages.get(parentPkg.packageName); - } - if (pps != null) { - pw.print(prefix); pw.print(" parentPackage="); - pw.println(pps.realName != null ? pps.realName : pps.name); - } - } else if (ps.pkg.childPackages != null) { - pw.print(prefix); pw.print(" childPackages=["); - final int childCount = ps.pkg.childPackages.size(); - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = ps.pkg.childPackages.get(i); - PackageSetting cps = mPackages.get(childPkg.packageName); - if (cps == null || !cps.codePathString.equals(childPkg.codePath)) { - cps = mDisabledSysPackages.get(childPkg.packageName); - } - if (cps != null) { - if (i > 0) { - pw.print(", "); - } - pw.print(cps.realName != null ? cps.realName : cps.name); - } - } - pw.println("]"); - } - pw.print(prefix); pw.print(" versionName="); pw.println(ps.pkg.mVersionName); - pw.print(prefix); pw.print(" splits="); dumpSplitNames(pw, ps.pkg); pw.println(); - final int apkSigningVersion = ps.pkg.mSigningDetails.signatureSchemeVersion; + if (pkg != null) { + pw.print(prefix); pw.print(" versionName="); pw.println(pkg.getVersionName()); + pw.print(prefix); pw.print(" splits="); dumpSplitNames(pw, pkg); pw.println(); + final int apkSigningVersion = pkg.getSigningDetails().signatureSchemeVersion; pw.print(prefix); pw.print(" apkSigningVersion="); pw.println(apkSigningVersion); + // TODO(b/135203078): Is there anything to print here with AppInfo removed? pw.print(prefix); pw.print(" applicationInfo="); - pw.println(ps.pkg.applicationInfo.toString()); - pw.print(prefix); pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags, + pw.println(pkg.toAppInfoWithoutState().toString()); + pw.print(prefix); pw.print(" flags="); printFlags(pw, pkg.getFlags(), FLAG_DUMP_SPEC); pw.println(); - if (ps.pkg.applicationInfo.privateFlags != 0) { + if (pkg.getPrivateFlags() != 0) { pw.print(prefix); pw.print(" privateFlags="); printFlags(pw, - ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println(); + pkg.getPrivateFlags(), PRIVATE_FLAG_DUMP_SPEC); pw.println(); } - pw.print(prefix); pw.print(" forceQueryable="); pw.println(ps.pkg.mForceQueryable); - if (ps.pkg.mQueriesPackages != null) { - pw.append(prefix).append(" queriesPackages=").println(ps.pkg.mQueriesPackages); + pw.print(prefix); pw.print(" forceQueryable="); pw.println(ps.pkg.isForceQueryable()); + if (ps.pkg.getQueriesPackages() != null) { + pw.append(prefix).append(" queriesPackages=").println(ps.pkg.getQueriesPackages()); } - if (ps.pkg.mQueriesIntents != null) { - pw.append(prefix).append(" queriesIntents=").println(ps.pkg.mQueriesIntents); + if (ps.pkg.getQueriesIntents() != null) { + pw.append(prefix).append(" queriesIntents=").println(ps.pkg.getQueriesIntents()); } - pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); + pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.getDataDir()); pw.print(prefix); pw.print(" supportsScreens=["); boolean first = true; - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) { if (!first) pw.print(", "); first = false; pw.print("small"); } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) { if (!first) pw.print(", "); first = false; pw.print("medium"); } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { if (!first) pw.print(", "); first = false; pw.print("large"); } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { if (!first) pw.print(", "); first = false; pw.print("xlarge"); } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { if (!first) pw.print(", "); first = false; pw.print("resizeable"); } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { if (!first) pw.print(", "); first = false; pw.print("anyDensity"); } pw.println("]"); - if (ps.pkg.libraryNames != null && ps.pkg.libraryNames.size() > 0) { + List<String> libraryNames = pkg.getLibraryNames(); + if (libraryNames != null && libraryNames.size() > 0) { pw.print(prefix); pw.println(" dynamic libraries:"); - for (int i = 0; i<ps.pkg.libraryNames.size(); i++) { + for (int i = 0; i< libraryNames.size(); i++) { pw.print(prefix); pw.print(" "); - pw.println(ps.pkg.libraryNames.get(i)); + pw.println(libraryNames.get(i)); } } - if (ps.pkg.staticSharedLibName != null) { + if (pkg.getStaticSharedLibName() != null) { pw.print(prefix); pw.println(" static library:"); pw.print(prefix); pw.print(" "); - pw.print("name:"); pw.print(ps.pkg.staticSharedLibName); - pw.print(" version:"); pw.println(ps.pkg.staticSharedLibVersion); + pw.print("name:"); pw.print(pkg.getStaticSharedLibName()); + pw.print(" version:"); pw.println(pkg.getStaticSharedLibVersion()); } - if (ps.pkg.usesLibraries != null && ps.pkg.usesLibraries.size() > 0) { + + List<String> usesLibraries = pkg.getUsesLibraries(); + if (usesLibraries != null && usesLibraries.size() > 0) { pw.print(prefix); pw.println(" usesLibraries:"); - for (int i=0; i<ps.pkg.usesLibraries.size(); i++) { - pw.print(prefix); pw.print(" "); pw.println(ps.pkg.usesLibraries.get(i)); + for (int i=0; i< usesLibraries.size(); i++) { + pw.print(prefix); pw.print(" "); pw.println(usesLibraries.get(i)); } } - if (ps.pkg.usesStaticLibraries != null - && ps.pkg.usesStaticLibraries.size() > 0) { + + List<String> usesStaticLibraries = pkg.getUsesStaticLibraries(); + long[] usesStaticLibrariesVersions = pkg.getUsesStaticLibrariesVersions(); + if (usesStaticLibraries != null + && usesStaticLibraries.size() > 0) { pw.print(prefix); pw.println(" usesStaticLibraries:"); - for (int i=0; i<ps.pkg.usesStaticLibraries.size(); i++) { + for (int i=0; i< usesStaticLibraries.size(); i++) { pw.print(prefix); pw.print(" "); - pw.print(ps.pkg.usesStaticLibraries.get(i)); pw.print(" version:"); - pw.println(ps.pkg.usesStaticLibrariesVersions[i]); + pw.print(usesStaticLibraries.get(i)); pw.print(" version:"); + pw.println(usesStaticLibrariesVersions[i]); } } - if (ps.pkg.usesOptionalLibraries != null - && ps.pkg.usesOptionalLibraries.size() > 0) { + + List<String> usesOptionalLibraries = pkg.getUsesOptionalLibraries(); + if (usesOptionalLibraries != null + && usesOptionalLibraries.size() > 0) { pw.print(prefix); pw.println(" usesOptionalLibraries:"); - for (int i=0; i<ps.pkg.usesOptionalLibraries.size(); i++) { + for (int i=0; i< usesOptionalLibraries.size(); i++) { pw.print(prefix); pw.print(" "); - pw.println(ps.pkg.usesOptionalLibraries.get(i)); + pw.println(usesOptionalLibraries.get(i)); } } - if (ps.pkg.usesLibraryFiles != null - && ps.pkg.usesLibraryFiles.length > 0) { + + String[] usesLibraryFiles = pkg.getUsesLibraryFiles(); + if (usesLibraryFiles != null + && usesLibraryFiles.length > 0) { pw.print(prefix); pw.println(" usesLibraryFiles:"); - for (int i=0; i<ps.pkg.usesLibraryFiles.length; i++) { - pw.print(prefix); pw.print(" "); pw.println(ps.pkg.usesLibraryFiles[i]); + for (int i=0; i< usesLibraryFiles.length; i++) { + pw.print(prefix); pw.print(" "); pw.println(usesLibraryFiles[i]); } } } @@ -4709,40 +4614,40 @@ public final class Settings { pw.print(prefix); pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC); pw.println(); - if (ps.pkg != null && ps.pkg.mOverlayTarget != null) { - pw.print(prefix); pw.print(" overlayTarget="); pw.println(ps.pkg.mOverlayTarget); - pw.print(prefix); pw.print(" overlayCategory="); pw.println(ps.pkg.mOverlayCategory); + if (pkg != null && pkg.getOverlayTarget() != null) { + pw.print(prefix); pw.print(" overlayTarget="); pw.println(pkg.getOverlayTarget()); + pw.print(prefix); pw.print(" overlayCategory="); pw.println(pkg.getOverlayCategory()); } - if (ps.pkg != null && ps.pkg.permissions != null && ps.pkg.permissions.size() > 0) { - final ArrayList<PackageParser.Permission> perms = ps.pkg.permissions; + if (pkg != null && pkg.getPermissions() != null && pkg.getPermissions().size() > 0) { + final List<ParsedPermission> perms = pkg.getPermissions(); pw.print(prefix); pw.println(" declared permissions:"); for (int i=0; i<perms.size(); i++) { - PackageParser.Permission perm = perms.get(i); + ParsedPermission perm = perms.get(i); if (permissionNames != null - && !permissionNames.contains(perm.info.name)) { + && !permissionNames.contains(perm.getName())) { continue; } - pw.print(prefix); pw.print(" "); pw.print(perm.info.name); + pw.print(prefix); pw.print(" "); pw.print(perm.getName()); pw.print(": prot="); - pw.print(PermissionInfo.protectionToString(perm.info.protectionLevel)); - if ((perm.info.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) { + pw.print(PermissionInfo.protectionToString(perm.protectionLevel)); + if ((perm.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) { pw.print(", COSTS_MONEY"); } - if ((perm.info.flags&PermissionInfo.FLAG_REMOVED) != 0) { + if ((perm.flags&PermissionInfo.FLAG_REMOVED) != 0) { pw.print(", HIDDEN"); } - if ((perm.info.flags&PermissionInfo.FLAG_INSTALLED) != 0) { + if ((perm.flags&PermissionInfo.FLAG_INSTALLED) != 0) { pw.print(", INSTALLED"); } pw.println(); } } - if ((permissionNames != null || dumpAll) && ps.pkg != null - && ps.pkg.requestedPermissions != null - && ps.pkg.requestedPermissions.size() > 0) { - final ArrayList<String> perms = ps.pkg.requestedPermissions; + if ((permissionNames != null || dumpAll) && pkg != null + && pkg.getRequestedPermissions() != null + && pkg.getRequestedPermissions().size() > 0) { + final List<String> perms = pkg.getRequestedPermissions(); pw.print(prefix); pw.println(" requested permissions:"); for (int i=0; i<perms.size(); i++) { String perm = perms.get(i); @@ -5019,22 +4924,24 @@ public final class Settings { pw.print(mReadMessages.toString()); } - private static void dumpSplitNames(PrintWriter pw, PackageParser.Package pkg) { + private static void dumpSplitNames(PrintWriter pw, AndroidPackage pkg) { if (pkg == null) { pw.print("unknown"); } else { // [base:10, config.mdpi, config.xhdpi:12] pw.print("["); pw.print("base"); - if (pkg.baseRevisionCode != 0) { - pw.print(":"); pw.print(pkg.baseRevisionCode); + if (pkg.getBaseRevisionCode() != 0) { + pw.print(":"); pw.print(pkg.getBaseRevisionCode()); } - if (pkg.splitNames != null) { - for (int i = 0; i < pkg.splitNames.length; i++) { + String[] splitNames = pkg.getSplitNames(); + int[] splitRevisionCodes = pkg.getSplitRevisionCodes(); + if (splitNames != null) { + for (int i = 0; i < splitNames.length; i++) { pw.print(", "); - pw.print(pkg.splitNames[i]); - if (pkg.splitRevisionCodes[i] != 0) { - pw.print(":"); pw.print(pkg.splitRevisionCodes[i]); + pw.print(splitNames[i]); + if (splitRevisionCodes[i] != 0) { + pw.print(":"); pw.print(splitRevisionCodes[i]); } } } @@ -5110,22 +5017,23 @@ public final class Settings { } void dumpComponents(PrintWriter pw, String prefix, PackageSetting ps) { - dumpComponents(pw, prefix, ps, "activities:", ps.pkg.activities); - dumpComponents(pw, prefix, ps, "services:", ps.pkg.services); - dumpComponents(pw, prefix, ps, "receivers:", ps.pkg.receivers); - dumpComponents(pw, prefix, ps, "providers:", ps.pkg.providers); - dumpComponents(pw, prefix, ps, "instrumentations:", ps.pkg.instrumentation); + // TODO(b/135203078): ParsedComponent toString methods for dumping + dumpComponents(pw, prefix, "activities:", ps.pkg.getActivities()); + dumpComponents(pw, prefix, "services:", ps.pkg.getServices()); + dumpComponents(pw, prefix, "receivers:", ps.pkg.getReceivers()); + dumpComponents(pw, prefix, "providers:", ps.pkg.getProviders()); + dumpComponents(pw, prefix, "instrumentations:", ps.pkg.getInstrumentations()); } - void dumpComponents(PrintWriter pw, String prefix, PackageSetting ps, - String label, List<? extends PackageParser.Component<?>> list) { + void dumpComponents(PrintWriter pw, String prefix, String label, + List<? extends ParsedComponent> list) { final int size = CollectionUtils.size(list); if (size == 0) { return; } pw.print(prefix);pw.println(label); for (int i = 0; i < size; i++) { - final PackageParser.Component<?> component = list.get(i); + final ParsedComponent component = list.get(i); pw.print(prefix);pw.print(" "); pw.println(component.getComponentName().flattenToShortString()); } diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java index 648051817295..0a42ccf1c5ba 100644 --- a/services/core/java/com/android/server/pm/SharedUserSetting.java +++ b/services/core/java/com/android/server/pm/SharedUserSetting.java @@ -18,7 +18,7 @@ package com.android.server.pm; import android.annotation.Nullable; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.service.pm.PackageServiceDumpProto; import android.util.ArraySet; import android.util.proto.ProtoOutputStream; @@ -46,7 +46,7 @@ public final class SharedUserSetting extends SettingBase { // that all apps within the sharedUser run in the same selinux context. int seInfoTargetSdkVersion; - final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>(); + final ArraySet<PackageSetting> packages = new ArraySet<>(); final PackageSignatures signatures = new PackageSignatures(); Boolean signaturesChanged; @@ -98,7 +98,7 @@ public final class SharedUserSetting extends SettingBase { // If this is the first package added to this shared user, temporarily (until next boot) use // its targetSdkVersion when assigning seInfo for the shared user. if ((packages.size() == 0) && (packageSetting.pkg != null)) { - seInfoTargetSdkVersion = packageSetting.pkg.applicationInfo.targetSdkVersion; + seInfoTargetSdkVersion = packageSetting.pkg.getTargetSdkVersion(); } if (packages.add(packageSetting)) { setFlags(this.pkgFlags | packageSetting.pkgFlags); @@ -106,11 +106,11 @@ public final class SharedUserSetting extends SettingBase { } } - public @Nullable List<PackageParser.Package> getPackages() { + public @Nullable List<AndroidPackage> getPackages() { if (packages == null || packages.size() == 0) { return null; } - final ArrayList<PackageParser.Package> pkgList = new ArrayList<>(packages.size()); + final ArrayList<AndroidPackage> pkgList = new ArrayList<>(packages.size()); for (PackageSetting ps : packages) { if ((ps == null) || (ps.pkg == null)) { continue; @@ -131,20 +131,20 @@ public final class SharedUserSetting extends SettingBase { * restrictive selinux domain. */ public void fixSeInfoLocked() { - final List<PackageParser.Package> pkgList = getPackages(); + final List<AndroidPackage> pkgList = getPackages(); if (pkgList == null || pkgList.size() == 0) { return; } - for (PackageParser.Package pkg : pkgList) { - if (pkg.applicationInfo.targetSdkVersion < seInfoTargetSdkVersion) { - seInfoTargetSdkVersion = pkg.applicationInfo.targetSdkVersion; + for (AndroidPackage pkg : pkgList) { + if (pkg.getTargetSdkVersion() < seInfoTargetSdkVersion) { + seInfoTargetSdkVersion = pkg.getTargetSdkVersion(); } } - for (PackageParser.Package pkg : pkgList) { + for (AndroidPackage pkg : pkgList) { final boolean isPrivileged = isPrivileged() | pkg.isPrivileged(); - pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged, - seInfoTargetSdkVersion); + pkg.mutate().setSeInfo(SELinuxMMAC.getSeInfo(pkg, isPrivileged, + seInfoTargetSdkVersion)); } } diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java index 0a6a43543860..c36b9938a8cd 100644 --- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java +++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.content.res.Resources; import android.os.SystemProperties; import android.os.UserHandle; @@ -191,15 +192,15 @@ class UserSystemPackageInstaller { return; } final boolean install = - (userWhitelist == null || userWhitelist.contains(pkg.packageName)) - && !pkg.applicationInfo.hiddenUntilInstalled; + (userWhitelist == null || userWhitelist.contains(pkg.getPackageName())) + && !pkg.isHiddenUntilInstalled(); if (isConsideredUpgrade && !isFirstBoot && !install) { return; // To be careful, we don’t uninstall apps during OTAs } final boolean changed = pmInt.setInstalled(pkg, userId, install); if (changed) { Slog.i(TAG, (install ? "Installed " : "Uninstalled ") - + pkg.packageName + " for user " + userId); + + pkg.getPackageName() + " for user " + userId); } }); } @@ -220,7 +221,7 @@ class UserSystemPackageInstaller { // Check whether all whitelisted packages are indeed on the system. for (String pkgName : allWhitelistedPackages) { - PackageParser.Package pkg = pmInt.getPackage(pkgName); + AndroidPackage pkg = pmInt.getPackage(pkgName); if (pkg == null) { Slog.w(TAG, pkgName + " is whitelisted but not present."); } else if (!pkg.isSystem()) { @@ -234,8 +235,8 @@ class UserSystemPackageInstaller { } final boolean doWtf = isEnforceMode(mode); pmInt.forEachPackage(pkg -> { - if (pkg.isSystem() && !allWhitelistedPackages.contains(pkg.manifestPackageName)) { - final String msg = "System package " + pkg.manifestPackageName + if (pkg.isSystem() && !allWhitelistedPackages.contains(pkg.getManifestPackageName())) { + final String msg = "System package " + pkg.getManifestPackageName() + " is not whitelisted using 'install-in-user-type' in SystemConfig " + "for any user types!"; if (doWtf) { @@ -344,7 +345,7 @@ class UserSystemPackageInstaller { if (shouldInstallPackage(pkg, mWhitelistedPackagesForUserTypes, whitelistedPackages, isImplicitWhitelistMode, isSystemUser)) { // Although the whitelist uses manifest names, this function returns packageNames. - installPackages.add(pkg.packageName); + installPackages.add(pkg.getPackageName()); } }); return installPackages; @@ -366,12 +367,12 @@ class UserSystemPackageInstaller { * @param isSystemUser whether the user is USER_SYSTEM (which gets special treatment). */ @VisibleForTesting - static boolean shouldInstallPackage(PackageParser.Package sysPkg, + static boolean shouldInstallPackage(AndroidPackage sysPkg, @NonNull ArrayMap<String, Long> userTypeWhitelist, @NonNull Set<String> userWhitelist, boolean isImplicitWhitelistMode, boolean isSystemUser) { - final String pkgName = sysPkg.manifestPackageName; + final String pkgName = sysPkg.getManifestPackageName(); boolean install = (isImplicitWhitelistMode && !userTypeWhitelist.containsKey(pkgName)) || userWhitelist.contains(pkgName); diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java index cc5aec2e113e..486cfeff0739 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -25,13 +25,13 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; import android.content.pm.dex.ArtManager; import android.content.pm.dex.ArtManager.ProfileType; import android.content.pm.dex.ArtManagerInternal; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.ISnapshotRuntimeProfileCallback; import android.content.pm.dex.PackageOptimizationInfo; +import android.content.pm.parsing.AndroidPackage; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -390,9 +390,10 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { * - create the current primary profile to save time at app startup time. * - copy the profiles from the associated dex metadata file to the reference profile. */ - public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user, + public void prepareAppProfiles( + AndroidPackage pkg, @UserIdInt int user, boolean updateReferenceProfileContent) { - final int appId = UserHandle.getAppId(pkg.applicationInfo.uid); + final int appId = UserHandle.getAppId(pkg.getUid()); if (user < 0) { Slog.wtf(TAG, "Invalid user id: " + user); return; @@ -415,23 +416,24 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath(); } synchronized (mInstaller) { - boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId, + boolean result = mInstaller.prepareAppProfile(pkg.getPackageName(), user, appId, profileName, codePath, dexMetadataPath); if (!result) { Slog.e(TAG, "Failed to prepare profile for " + - pkg.packageName + ":" + codePath); + pkg.getPackageName() + ":" + codePath); } } } } catch (InstallerException e) { - Slog.e(TAG, "Failed to prepare profile for " + pkg.packageName, e); + Slog.e(TAG, "Failed to prepare profile for " + pkg.getPackageName(), e); } } /** * Prepares the app profiles for a set of users. {@see ArtManagerService#prepareAppProfiles}. */ - public void prepareAppProfiles(PackageParser.Package pkg, int[] user, + public void prepareAppProfiles( + AndroidPackage pkg, int[] user, boolean updateReferenceProfileContent) { for (int i = 0; i < user.length; i++) { prepareAppProfiles(pkg, user[i], updateReferenceProfileContent); @@ -441,12 +443,12 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { /** * Clear the profiles for the given package. */ - public void clearAppProfiles(PackageParser.Package pkg) { + public void clearAppProfiles(AndroidPackage pkg) { try { ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg); for (int i = packageProfileNames.size() - 1; i >= 0; i--) { String profileName = packageProfileNames.valueAt(i); - mInstaller.clearAppProfiles(pkg.packageName, profileName); + mInstaller.clearAppProfiles(pkg.getPackageName(), profileName); } } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); @@ -456,15 +458,15 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { /** * Dumps the profiles for the given package. */ - public void dumpProfiles(PackageParser.Package pkg) { - final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + public void dumpProfiles(AndroidPackage pkg) { + final int sharedGid = UserHandle.getSharedAppGid(pkg.getUid()); try { ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg); for (int i = packageProfileNames.size() - 1; i >= 0; i--) { String codePath = packageProfileNames.keyAt(i); String profileName = packageProfileNames.valueAt(i); synchronized (mInstallLock) { - mInstaller.dumpProfiles(sharedGid, pkg.packageName, profileName, codePath); + mInstaller.dumpProfiles(sharedGid, pkg.getPackageName(), profileName, codePath); } } } catch (InstallerException e) { @@ -475,14 +477,13 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { /** * Compile layout resources in a given package. */ - public boolean compileLayouts(PackageParser.Package pkg) { + public boolean compileLayouts(AndroidPackage pkg) { try { - final String packageName = pkg.packageName; - final String apkPath = pkg.baseCodePath; - final ApplicationInfo appInfo = pkg.applicationInfo; - final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex"; - if (appInfo.isPrivilegedApp() || appInfo.isEmbeddedDexUsed() - || appInfo.isDefaultToDeviceProtectedStorage()) { + final String packageName = pkg.getPackageName(); + final String apkPath = pkg.getBaseCodePath(); + final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex"; + if (pkg.isPrivileged() || pkg.isEmbeddedDexUsed() + || pkg.isDefaultToDeviceProtectedStorage()) { // Privileged apps prefer to load trusted code so they don't use compiled views. // If the app is not privileged but prefers code integrity, also avoid compiling // views. @@ -496,7 +497,7 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { try { synchronized (mInstallLock) { return mInstaller.compileLayouts(apkPath, packageName, outDexFile, - appInfo.uid); + pkg.getUid()); } } finally { Binder.restoreCallingIdentity(callingId); @@ -512,15 +513,19 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { * Build the profiles names for all the package code paths (excluding resource only paths). * Return the map [code path -> profile name]. */ - private ArrayMap<String, String> getPackageProfileNames(PackageParser.Package pkg) { + private ArrayMap<String, String> getPackageProfileNames(AndroidPackage pkg) { ArrayMap<String, String> result = new ArrayMap<>(); - if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { - result.put(pkg.baseCodePath, ArtManager.getProfileName(null)); + if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0) { + result.put(pkg.getBaseCodePath(), ArtManager.getProfileName(null)); } - if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { - for (int i = 0; i < pkg.splitCodePaths.length; i++) { - if ((pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { - result.put(pkg.splitCodePaths[i], ArtManager.getProfileName(pkg.splitNames[i])); + + String[] splitCodePaths = pkg.getSplitCodePaths(); + int[] splitFlags = pkg.getSplitFlags(); + String[] splitNames = pkg.getSplitNames(); + if (!ArrayUtils.isEmpty(splitCodePaths)) { + for (int i = 0; i < splitCodePaths.length; i++) { + if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { + result.put(splitCodePaths[i], ArtManager.getProfileName(splitNames[i])); } } } diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index 41dcaa59047b..29183bb78f07 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -588,7 +588,7 @@ public class DexManager { // We found the package. Now record the usage for all declared ISAs. boolean update = false; - for (String isa : getAppDexInstructionSets(info)) { + for (String isa : getAppDexInstructionSets(info.primaryCpuAbi, info.secondaryCpuAbi)) { boolean newUpdate = mPackageDexUsage.record(searchResult.mOwningPackageName, dexPath, userId, isa, isUsedByOtherApps, /*primaryOrSplit*/ false, searchResult.mOwningPackageName, diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java index 5a473c1819c1..6e6b137d23a2 100644 --- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java +++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java @@ -18,10 +18,12 @@ package com.android.server.pm.dex; import android.content.pm.ApplicationInfo; import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.AndroidPackage; import android.util.Slog; import android.util.SparseArray; import com.android.internal.os.ClassLoaderFactory; +import com.android.internal.util.ArrayUtils; import java.io.File; import java.util.List; @@ -66,7 +68,7 @@ public final class DexoptUtils { * {@link android.app.LoadedApk#makePaths( * android.app.ActivityThread, boolean, ApplicationInfo, List, List)}. */ - public static String[] getClassLoaderContexts(ApplicationInfo info, + public static String[] getClassLoaderContexts(AndroidPackage pkg, List<SharedLibraryInfo> sharedLibraries, boolean[] pathsWithCode) { // The base class loader context contains only the shared library. String sharedLibrariesContext = ""; @@ -75,8 +77,8 @@ public final class DexoptUtils { } String baseApkContextClassLoader = encodeClassLoader( - "", info.classLoaderName, sharedLibrariesContext); - if (info.getSplitCodePaths() == null) { + "", pkg.getAppInfoClassLoaderName(), sharedLibrariesContext); + if (pkg.getSplitCodePaths() == null) { // The application has no splits. return new String[] {baseApkContextClassLoader}; } @@ -84,11 +86,11 @@ public final class DexoptUtils { // The application has splits. Compute their class loader contexts. // First, cache the relative paths of the splits and do some sanity checks - String[] splitRelativeCodePaths = getSplitRelativeCodePaths(info); + String[] splitRelativeCodePaths = getSplitRelativeCodePaths(pkg); // The splits have an implicit dependency on the base apk. // This means that we have to add the base apk file in addition to the shared libraries. - String baseApkName = new File(info.getBaseCodePath()).getName(); + String baseApkName = new File(pkg.getBaseCodePath()).getName(); String baseClassPath = baseApkName; // The result is stored in classLoaderContexts. @@ -97,7 +99,11 @@ public final class DexoptUtils { String[] classLoaderContexts = new String[/*base apk*/ 1 + splitRelativeCodePaths.length]; classLoaderContexts[0] = pathsWithCode[0] ? baseApkContextClassLoader : null; - if (!info.requestsIsolatedSplitLoading() || info.splitDependencies == null) { + SparseArray<int[]> splitDependencies = pkg.getSplitDependencies(); + + if (!pkg.requestsIsolatedSplitLoading() + || splitDependencies == null + || splitDependencies.size() == 0) { // If the app didn't request for the splits to be loaded in isolation or if it does not // declare inter-split dependencies, then all the splits will be loaded in the base // apk class loader (in the order of their definition). @@ -105,7 +111,7 @@ public final class DexoptUtils { for (int i = 1; i < classLoaderContexts.length; i++) { if (pathsWithCode[i]) { classLoaderContexts[i] = encodeClassLoader( - classpath, info.classLoaderName, sharedLibrariesContext); + classpath, pkg.getAppInfoClassLoaderName(), sharedLibrariesContext); } else { classLoaderContexts[i] = null; } @@ -132,11 +138,10 @@ public final class DexoptUtils { String[] splitClassLoaderEncodingCache = new String[splitRelativeCodePaths.length]; for (int i = 0; i < splitRelativeCodePaths.length; i++) { splitClassLoaderEncodingCache[i] = encodeClassLoader(splitRelativeCodePaths[i], - info.splitClassLoaderNames[i]); + pkg.getSplitClassLoaderNames()[i]); } String splitDependencyOnBase = encodeClassLoader( - baseClassPath, info.classLoaderName); - SparseArray<int[]> splitDependencies = info.splitDependencies; + baseClassPath, pkg.getClassLoaderName()); // Note that not all splits have dependencies (e.g. configuration splits) // The splits without dependencies will have classLoaderContexts[config_split_index] @@ -154,7 +159,8 @@ public final class DexoptUtils { // We also need to add the class loader of the current split which should // come first in the context. for (int i = 1; i < classLoaderContexts.length; i++) { - String splitClassLoader = encodeClassLoader("", info.splitClassLoaderNames[i - 1]); + String splitClassLoader = encodeClassLoader("", + pkg.getSplitClassLoaderNames()[i - 1]); if (pathsWithCode[i]) { // If classLoaderContexts[i] is null it means that the split does not have // any dependency. In this case its context equals its declared class loader. @@ -394,11 +400,11 @@ public final class DexoptUtils { * Returns the relative paths of the splits declared by the application {@code info}. * Assumes that the application declares a non-null array of splits. */ - private static String[] getSplitRelativeCodePaths(ApplicationInfo info) { - String baseCodePath = new File(info.getBaseCodePath()).getParent(); - String[] splitCodePaths = info.getSplitCodePaths(); - String[] splitRelativeCodePaths = new String[splitCodePaths.length]; - for (int i = 0; i < splitCodePaths.length; i++) { + private static String[] getSplitRelativeCodePaths(AndroidPackage pkg) { + String baseCodePath = new File(pkg.getBaseCodePath()).getParent(); + String[] splitCodePaths = pkg.getSplitCodePaths(); + String[] splitRelativeCodePaths = new String[ArrayUtils.size(splitCodePaths)]; + for (int i = 0; i < splitRelativeCodePaths.length; i++) { File pathFile = new File(splitCodePaths[i]); splitRelativeCodePaths[i] = pathFile.getName(); // Sanity check that the base paths of the splits are all the same. diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java index 8d8e17e92b3d..b7443f36e494 100644 --- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java +++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java @@ -16,10 +16,10 @@ package com.android.server.pm.dex; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.os.Binder; import android.util.Log; + import com.android.internal.annotations.GuardedBy; import com.android.server.pm.Installer; @@ -33,19 +33,18 @@ public class ViewCompiler { mInstaller = installer; } - public boolean compileLayouts(PackageParser.Package pkg) { + public boolean compileLayouts(AndroidPackage pkg) { try { - final String packageName = pkg.packageName; - final String apkPath = pkg.baseCodePath; - final ApplicationInfo appInfo = pkg.applicationInfo; - final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex"; + final String packageName = pkg.getPackageName(); + final String apkPath = pkg.getBaseCodePath(); + final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex"; Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath + ") to " + outDexFile); long callingId = Binder.clearCallingIdentity(); try { synchronized (mInstallLock) { return mInstaller.compileLayouts(apkPath, packageName, outDexFile, - appInfo.uid); + pkg.getUid()); } } finally { Binder.restoreCallingIdentity(callingId); diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java index c39dcfefb2e8..9668c21d0fab 100644 --- a/services/core/java/com/android/server/pm/permission/BasePermission.java +++ b/services/core/java/com/android/server/pm/permission/BasePermission.java @@ -29,10 +29,12 @@ import static com.android.server.pm.Settings.TAG_ITEM; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.pm.PackageParser; -import android.content.pm.PackageParser.Permission; +import android.content.pm.PackageManagerInternal; import android.content.pm.PermissionInfo; import android.content.pm.Signature; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.PackageInfoUtils; import android.os.UserHandle; import android.util.Log; import android.util.Slog; @@ -89,7 +91,7 @@ public final class BasePermission { int protectionLevel; - PackageParser.Permission perm; + ParsedPermission perm; PermissionInfo pendingPermissionInfo; @@ -113,12 +115,6 @@ public final class BasePermission { protectionLevel = PermissionInfo.PROTECTION_SIGNATURE; } - @Override - public String toString() { - return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name - + "}"; - } - public String getName() { return name; } @@ -144,7 +140,7 @@ public final class BasePermission { this.gids = gids; this.perUser = perUser; } - public void setPermission(@Nullable Permission perm) { + public void setPermission(@Nullable ParsedPermission perm) { this.perm = perm; } public void setSourcePackageSetting(PackageSettingBase sourcePackageSetting) { @@ -165,13 +161,16 @@ public final class BasePermission { public int calculateFootprint(BasePermission perm) { if (uid == perm.uid) { - return perm.name.length() + perm.perm.info.calculateFootprint(); + return perm.name.length() + perm.perm.calculateFootprint(); } return 0; } - public boolean isPermission(Permission perm) { - return this.perm == perm; + public boolean isPermission(@NonNull ParsedPermission perm) { + if (this.perm == null) { + return false; + } + return Objects.equals(this.perm.className, perm.className); } public boolean isDynamic() { @@ -189,29 +188,24 @@ public final class BasePermission { } public boolean isRemoved() { - return perm != null && perm.info != null - && (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0; + return perm != null && (perm.flags & PermissionInfo.FLAG_REMOVED) != 0; } public boolean isSoftRestricted() { - return perm != null && perm.info != null - && (perm.info.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0; + return perm != null && (perm.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0; } public boolean isHardRestricted() { - return perm != null && perm.info != null - && (perm.info.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0; + return perm != null && (perm.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0; } public boolean isHardOrSoftRestricted() { - return perm != null && perm.info != null - && (perm.info.flags & (PermissionInfo.FLAG_HARD_RESTRICTED + return perm != null && (perm.flags & (PermissionInfo.FLAG_HARD_RESTRICTED | PermissionInfo.FLAG_SOFT_RESTRICTED)) != 0; } public boolean isImmutablyRestricted() { - return perm != null && perm.info != null - && (perm.info.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0; + return perm != null && (perm.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0; } public boolean isSignature() { @@ -300,13 +294,12 @@ public final class BasePermission { (this.protectionLevel != protectionLevel || perm == null || uid != tree.uid - || !perm.owner.equals(tree.perm.owner) - || !comparePermissionInfos(perm.info, info)); + || !Objects.equals(perm.getPackageName(), tree.perm.getPackageName()) + || !comparePermissionInfos(perm, info)); this.protectionLevel = protectionLevel; info = new PermissionInfo(info); info.protectionLevel = protectionLevel; - perm = new PackageParser.Permission(tree.perm.owner, info); - perm.info.packageName = tree.perm.info.packageName; + perm = new ParsedPermission(tree.perm); uid = tree.uid; return changed; } @@ -319,71 +312,89 @@ public final class BasePermission { final BasePermission tree = findPermissionTree(permissionTrees, name); if (tree != null && tree.perm != null) { sourcePackageSetting = tree.sourcePackageSetting; - perm = new PackageParser.Permission(tree.perm.owner, - new PermissionInfo(pendingPermissionInfo)); - perm.info.packageName = tree.perm.info.packageName; - perm.info.name = name; + perm = new ParsedPermission(tree.perm); + perm.protectionLevel = pendingPermissionInfo.protectionLevel; + perm.flags = pendingPermissionInfo.flags; + perm.setGroup(pendingPermissionInfo.group); + perm.backgroundPermission = pendingPermissionInfo.backgroundPermission; + perm.descriptionRes = pendingPermissionInfo.descriptionRes; + perm.requestRes = pendingPermissionInfo.requestRes; + perm.setPackageName(tree.perm.getPackageName()); + perm.setName(name); uid = tree.uid; } } } - static BasePermission createOrUpdate(@Nullable BasePermission bp, @NonNull Permission p, - @NonNull PackageParser.Package pkg, Collection<BasePermission> permissionTrees, + static BasePermission createOrUpdate(PackageManagerInternal packageManagerInternal, + @Nullable BasePermission bp, @NonNull ParsedPermission p, + @NonNull AndroidPackage pkg, Collection<BasePermission> permissionTrees, boolean chatty) { - final PackageSettingBase pkgSetting = (PackageSettingBase) pkg.mExtras; + final PackageSettingBase pkgSetting = + (PackageSettingBase) packageManagerInternal.getPackageSetting(pkg.getPackageName()); // Allow system apps to redefine non-system permissions - if (bp != null && !Objects.equals(bp.sourcePackageName, p.info.packageName)) { - final boolean currentOwnerIsSystem = (bp.perm != null - && bp.perm.owner.isSystem()); - if (p.owner.isSystem()) { + if (bp != null && !Objects.equals(bp.sourcePackageName, p.getPackageName())) { + final boolean currentOwnerIsSystem; + if (bp.perm == null) { + currentOwnerIsSystem = false; + } else { + AndroidPackage currentPackage = packageManagerInternal.getPackage( + bp.perm.getPackageName()); + if (currentPackage == null) { + currentOwnerIsSystem = false; + } else { + currentOwnerIsSystem = currentPackage.isSystem(); + } + } + + if (pkg.isSystem()) { if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) { // It's a built-in permission and no owner, take ownership now + p.flags |= PermissionInfo.FLAG_INSTALLED; bp.sourcePackageSetting = pkgSetting; bp.perm = p; - bp.uid = pkg.applicationInfo.uid; - bp.sourcePackageName = p.info.packageName; - p.info.flags |= PermissionInfo.FLAG_INSTALLED; + bp.uid = pkg.getUid(); + bp.sourcePackageName = p.getPackageName(); } else if (!currentOwnerIsSystem) { - String msg = "New decl " + p.owner + " of permission " - + p.info.name + " is system; overriding " + bp.sourcePackageName; + String msg = "New decl " + pkg + " of permission " + + p.getName() + " is system; overriding " + bp.sourcePackageName; PackageManagerService.reportSettingsProblem(Log.WARN, msg); bp = null; } } } if (bp == null) { - bp = new BasePermission(p.info.name, p.info.packageName, TYPE_NORMAL); + bp = new BasePermission(p.getName(), p.getPackageName(), TYPE_NORMAL); } StringBuilder r = null; if (bp.perm == null) { if (bp.sourcePackageName == null - || bp.sourcePackageName.equals(p.info.packageName)) { - final BasePermission tree = findPermissionTree(permissionTrees, p.info.name); + || bp.sourcePackageName.equals(p.getPackageName())) { + final BasePermission tree = findPermissionTree(permissionTrees, p.getName()); if (tree == null - || tree.sourcePackageName.equals(p.info.packageName)) { + || tree.sourcePackageName.equals(p.getPackageName())) { + p.flags |= PermissionInfo.FLAG_INSTALLED; bp.sourcePackageSetting = pkgSetting; bp.perm = p; - bp.uid = pkg.applicationInfo.uid; - bp.sourcePackageName = p.info.packageName; - p.info.flags |= PermissionInfo.FLAG_INSTALLED; + bp.uid = pkg.getUid(); + bp.sourcePackageName = p.getPackageName(); if (chatty) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } - r.append(p.info.name); + r.append(p.getName()); } } else { - Slog.w(TAG, "Permission " + p.info.name + " from package " - + p.info.packageName + " ignored: base tree " + Slog.w(TAG, "Permission " + p.getName() + " from package " + + p.getPackageName() + " ignored: base tree " + tree.name + " is from package " + tree.sourcePackageName); } } else { - Slog.w(TAG, "Permission " + p.info.name + " from package " - + p.info.packageName + " ignored: original from " + Slog.w(TAG, "Permission " + p.getName() + " from package " + + p.getPackageName() + " ignored: original from " + bp.sourcePackageName); } } else if (chatty) { @@ -393,10 +404,10 @@ public final class BasePermission { r.append(' '); } r.append("DUP:"); - r.append(p.info.name); + r.append(p.getName()); } - if (bp.perm == p) { - bp.protectionLevel = p.info.protectionLevel; + if (bp.perm != null && Objects.equals(bp.perm.className, p.className)) { + bp.protectionLevel = p.protectionLevel; } if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) { Log.d(TAG, " Permissions: " + r); @@ -420,17 +431,17 @@ public final class BasePermission { throw new SecurityException("No permission tree found for " + permName); } - public void enforceDeclaredUsedAndRuntimeOrDevelopment(PackageParser.Package pkg) { - final PackageSetting pkgSetting = (PackageSetting) pkg.mExtras; + public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg, + PackageSetting pkgSetting) { final PermissionsState permsState = pkgSetting.getPermissionsState(); - int index = pkg.requestedPermissions.indexOf(name); + int index = pkg.getRequestedPermissions().indexOf(name); if (!permsState.hasRequestedPermission(name) && index == -1) { - throw new SecurityException("Package " + pkg.packageName + throw new SecurityException("Package " + pkg.getPackageName() + " has not requested permission " + name); } if (!isRuntime() && !isDevelopment()) { - throw new SecurityException("Permission " + name - + " requested by " + pkg.packageName + " is not a changeable permission type"); + throw new SecurityException("Permission " + name + " requested by " + + pkg.getPackageName() + " is not a changeable permission type"); } } @@ -448,12 +459,12 @@ public final class BasePermission { public @Nullable PermissionInfo generatePermissionInfo(@NonNull String groupName, int flags) { if (groupName == null) { - if (perm == null || perm.info.group == null) { + if (perm == null || perm.getGroup() == null) { return generatePermissionInfo(protectionLevel, flags); } } else { - if (perm != null && groupName.equals(perm.info.group)) { - return PackageParser.generatePermissionInfo(perm, flags); + if (perm != null && groupName.equals(perm.getGroup())) { + return PackageInfoUtils.generatePermissionInfo(perm, flags); } } return null; @@ -463,8 +474,8 @@ public final class BasePermission { PermissionInfo permissionInfo; if (perm != null) { final boolean protectionLevelChanged = protectionLevel != adjustedProtectionLevel; - permissionInfo = PackageParser.generatePermissionInfo(perm, flags); - if (protectionLevelChanged && permissionInfo == perm.info) { + permissionInfo = PackageInfoUtils.generatePermissionInfo(perm, flags); + if (protectionLevelChanged) { // if we return different protection level, don't use the cached info permissionInfo = new PermissionInfo(permissionInfo); permissionInfo.protectionLevel = adjustedProtectionLevel; @@ -544,14 +555,18 @@ public final class BasePermission { serializer.attribute(null, "protection", Integer.toString(protectionLevel)); } if (type == BasePermission.TYPE_DYNAMIC) { - final PermissionInfo pi = perm != null ? perm.info : pendingPermissionInfo; - if (pi != null) { + if (perm != null || pendingPermissionInfo != null) { serializer.attribute(null, "type", "dynamic"); - if (pi.icon != 0) { - serializer.attribute(null, "icon", Integer.toString(pi.icon)); + int icon = perm != null ? perm.icon : pendingPermissionInfo.icon; + CharSequence nonLocalizedLabel = perm != null + ? perm.nonLocalizedLabel + : pendingPermissionInfo.nonLocalizedLabel; + + if (icon != 0) { + serializer.attribute(null, "icon", Integer.toString(icon)); } - if (pi.nonLocalizedLabel != null) { - serializer.attribute(null, "label", pi.nonLocalizedLabel.toString()); + if (nonLocalizedLabel != null) { + serializer.attribute(null, "label", nonLocalizedLabel.toString()); } } } @@ -571,14 +586,14 @@ public final class BasePermission { return s1.equals(s2); } - private static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) { + private static boolean comparePermissionInfos(ParsedPermission pi1, PermissionInfo pi2) { if (pi1.icon != pi2.icon) return false; if (pi1.logo != pi2.logo) return false; if (pi1.protectionLevel != pi2.protectionLevel) return false; - if (!compareStrings(pi1.name, pi2.name)) return false; + if (!compareStrings(pi1.getName(), pi2.name)) return false; if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false; // We'll take care of setting this one. - if (!compareStrings(pi1.packageName, pi2.packageName)) return false; + if (!compareStrings(pi1.getPackageName(), pi2.packageName)) return false; // These are not currently stored in settings. //if (!compareStrings(pi1.group, pi2.group)) return false; //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false; @@ -614,9 +629,9 @@ public final class BasePermission { pw.println(PermissionInfo.protectionToString(protectionLevel)); if (perm != null) { pw.print(" perm="); pw.println(perm); - if ((perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0 - || (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) { - pw.print(" flags=0x"); pw.println(Integer.toHexString(perm.info.flags)); + if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0 + || (perm.flags & PermissionInfo.FLAG_REMOVED) != 0) { + pw.print(" flags=0x"); pw.println(Integer.toHexString(perm.flags)); } } if (sourcePackageSetting != null) { @@ -628,4 +643,20 @@ public final class BasePermission { } return true; } + + @Override + public String toString() { + return "BasePermission{" + + "name='" + name + '\'' + + ", type=" + type + + ", sourcePackageName='" + sourcePackageName + '\'' + + ", sourcePackageSetting=" + sourcePackageSetting + + ", protectionLevel=" + protectionLevel + + ", perm=" + perm + + ", pendingPermissionInfo=" + pendingPermissionInfo + + ", uid=" + uid + + ", gids=" + Arrays.toString(gids) + + ", perUser=" + perUser + + '}'; + } } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 2ffba45be4a3..5adb64876ad4 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -63,10 +63,13 @@ import android.content.pm.PackageManager.PermissionInfoFlags; import android.content.pm.PackageManager.PermissionWhitelistFlags; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.Package; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; +import android.content.pm.parsing.PackageInfoUtils; import android.content.pm.permission.SplitPermissionInfoParcelable; import android.metrics.LogMaker; import android.os.Binder; @@ -419,7 +422,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - @Nullable BasePermission getPermission(String permName) { + @Nullable + BasePermission getPermission(String permName) { synchronized (mLock) { return mSettings.getPermissionLocked(permName); } @@ -453,10 +457,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { } synchronized (mLock) { final int n = mSettings.mPermissionGroups.size(); - final ArrayList<PermissionGroupInfo> out = - new ArrayList<PermissionGroupInfo>(n); - for (PackageParser.PermissionGroup pg : mSettings.mPermissionGroups.values()) { - out.add(PackageParser.generatePermissionGroupInfo(pg, flags)); + final ArrayList<PermissionGroupInfo> out = new ArrayList<>(n); + for (ParsedPermissionGroup pg : mSettings.mPermissionGroups.values()) { + out.add(PackageInfoUtils.generatePermissionGroupInfo(pg, flags)); } return new ParceledListSlice<>(out); } @@ -472,7 +475,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { return null; } synchronized (mLock) { - return PackageParser.generatePermissionGroupInfo( + return PackageInfoUtils.generatePermissionGroupInfo( mSettings.mPermissionGroups.get(groupName), flags); } } @@ -596,8 +599,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { false, // requirePermissionWhenSameUser "getPermissionFlags"); - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); - if (pkg == null || pkg.mExtras == null) { + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); + if (pkg == null) { + return 0; + } + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); + if (ps == null) { return 0; } synchronized (mLock) { @@ -608,7 +616,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) { return 0; } - final PackageSetting ps = (PackageSetting) pkg.mExtras; PermissionsState permissionsState = ps.getPermissionsState(); return permissionsState.getPermissionFlags(permName, userId); } @@ -695,8 +702,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { flagValues &= ~PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; } - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); - if (pkg == null || pkg.mExtras == null) { + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + packageName); + if (pkg == null || ps == null) { Log.e(TAG, "Unknown package: " + packageName); return; } @@ -712,7 +721,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Unknown permission: " + permName); } - final PackageSetting ps = (PackageSetting) pkg.mExtras; final PermissionsState permissionsState = ps.getPermissionsState(); final boolean hadState = permissionsState.getRuntimePermissionState(permName, userId) != null; @@ -725,11 +733,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Install and runtime permissions are stored in different places, // so figure out what permission changed and persist the change. if (permissionsState.getInstallPermissionState(permName) != null) { - callback.onInstallPermissionUpdatedNotifyListener(pkg.applicationInfo.uid); + callback.onInstallPermissionUpdatedNotifyListener(pkg.getUid()); } else if (permissionsState.getRuntimePermissionState(permName, userId) != null || hadState) { - callback.onPermissionUpdatedNotifyListener(new int[] { userId }, false, - pkg.applicationInfo.uid); + callback.onPermissionUpdatedNotifyListener(new int[]{userId}, false, + pkg.getUid()); } } } @@ -761,18 +769,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { ? flagValues : flagValues & ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; final boolean[] changed = new boolean[1]; - mPackageManagerInt.forEachPackage(new Consumer<PackageParser.Package>() { - @Override - public void accept(Package pkg) { - final PackageSetting ps = (PackageSetting) pkg.mExtras; - if (ps == null) { - return; - } - final PermissionsState permissionsState = ps.getPermissionsState(); - changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions( - userId, effectiveFlagMask, effectiveFlagValues); - mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid); + mPackageManagerInt.forEachPackage(pkg -> { + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); + if (ps == null) { + return; } + final PermissionsState permissionsState = ps.getPermissionsState(); + changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions( + userId, effectiveFlagMask, effectiveFlagValues); + mOnPermissionChangeListeners.onPermissionsChanged(pkg.getUid()); }); if (changed[0]) { @@ -802,17 +808,17 @@ public class PermissionManagerService extends IPermissionManager.Stub { } private int checkPermissionImpl(String permName, String pkgName, int userId) { - final PackageParser.Package pkg = mPackageManagerInt.getPackage(pkgName); + final AndroidPackage pkg = mPackageManagerInt.getPackage(pkgName); if (pkg == null) { return PackageManager.PERMISSION_DENIED; } return checkPermissionInternal(pkg, true, permName, userId); } - private int checkPermissionInternal(@NonNull Package pkg, boolean isPackageExplicit, + private int checkPermissionInternal(@NonNull AndroidPackage pkg, boolean isPackageExplicit, @NonNull String permissionName, @UserIdInt int userId) { final int callingUid = getCallingUid(); - if (isPackageExplicit || pkg.mSharedUserId == null) { + if (isPackageExplicit || pkg.getSharedUserId() == null) { if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) { return PackageManager.PERMISSION_DENIED; } @@ -822,8 +828,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid); - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final int uid = UserHandle.getUid(userId, pkg.getUid()); + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); if (ps == null) { return PackageManager.PERMISSION_DENIED; } @@ -878,7 +885,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } private int checkUidPermissionImpl(String permName, int uid) { - final PackageParser.Package pkg = mPackageManagerInt.getPackage(uid); + final AndroidPackage pkg = mPackageManagerInt.getPackage(uid); return checkUidPermissionInternal(pkg, uid, permName); } @@ -889,7 +896,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * * @see SystemConfig#getSystemPermissions() */ - private int checkUidPermissionInternal(@Nullable Package pkg, int uid, + private int checkUidPermissionInternal(@Nullable AndroidPackage pkg, int uid, @NonNull String permissionName) { if (pkg != null) { final int userId = UserHandle.getUserId(uid); @@ -953,7 +960,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { "getWhitelistedRestrictedPermissions for user " + userId); } - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); if (pkg == null) { return null; } @@ -986,7 +993,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { final long identity = Binder.clearCallingIdentity(); try { final PermissionsState permissionsState = - PackageManagerServiceUtils.getPermissionsState(pkg); + PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg); if (permissionsState == null) { return null; } @@ -1004,9 +1011,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { ArrayList<String> whitelistedPermissions = null; - final int permissionCount = pkg.requestedPermissions.size(); + final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions()); for (int i = 0; i < permissionCount; i++) { - final String permissionName = pkg.requestedPermissions.get(i); + final String permissionName = pkg.getRequestedPermissions().get(i); final int currentFlags = permissionsState.getPermissionFlags(permissionName, userId); if ((currentFlags & queryFlags) != 0) { @@ -1103,7 +1110,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { "setWhitelistedRestrictedPermissions for user " + userId); } - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); if (pkg == null) { return false; } @@ -1132,7 +1139,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS); } final List<String> whitelistedPermissions = - getWhitelistedRestrictedPermissions(pkg.packageName, flags, userId); + getWhitelistedRestrictedPermissions(pkg.getPackageName(), flags, userId); if (permissions == null || permissions.isEmpty()) { if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) { return true; @@ -1206,8 +1213,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { false, // requirePermissionWhenSameUser "grantRuntimePermission"); - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); - if (pkg == null || pkg.mExtras == null) { + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + packageName); + if (pkg == null || ps == null) { Log.e(TAG, "Unknown package: " + packageName); return; } @@ -1222,21 +1231,19 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Unknown package: " + packageName); } - bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg); + bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps); // If a permission review is required for legacy apps we represent // their permissions as always granted runtime ones since we need // to keep the review required permission flag per user while an // install permission's state is shared across all users. - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && bp.isRuntime()) { return; } - final int uid = UserHandle.getUid(userId, - UserHandle.getAppId(pkg.applicationInfo.uid)); + final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid())); - final PackageSetting ps = (PackageSetting) pkg.mExtras; final PermissionsState permissionsState = ps.getPermissionsState(); final int flags = permissionsState.getPermissionFlags(permName, userId); @@ -1259,7 +1266,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext, - pkg.applicationInfo, UserHandle.of(userId), permName).mayGrantPermission()) { + pkg.toAppInfoWithoutState(), UserHandle.of(userId), permName) + .mayGrantPermission()) { Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package " + packageName); return; @@ -1282,7 +1290,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { + permName + " for package " + packageName); } - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) { Slog.w(TAG, "Cannot grant runtime permission to a legacy app"); return; } @@ -1295,7 +1303,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: { if (callback != null) { - callback.onGidsChanged(UserHandle.getAppId(pkg.applicationInfo.uid), userId); + callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId); } } break; @@ -1368,8 +1376,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { false, // requirePermissionWhenSameUser "revokeRuntimePermission"); - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); - if (pkg == null || pkg.mExtras == null) { + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + packageName); + if (pkg == null || ps == null) { Log.e(TAG, "Unknown package: " + packageName); return; } @@ -1381,18 +1391,17 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Unknown permission: " + permName); } - bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg); + bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps); // If a permission review is required for legacy apps we represent // their permissions as always granted runtime ones since we need // to keep the review required permission flag per user while an // install permission's state is shared across all users. - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && bp.isRuntime()) { return; } - final PackageSetting ps = (PackageSetting) pkg.mExtras; final PermissionsState permissionsState = ps.getPermissionsState(); final int flags = permissionsState.getPermissionFlags(permName, userId); @@ -1435,7 +1444,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (callback != null) { callback.onPermissionRevoked(UserHandle.getUid(userId, - UserHandle.getAppId(pkg.applicationInfo.uid)), userId); + UserHandle.getAppId(pkg.getUid())), userId); } if (bp.isRuntime()) { @@ -1460,7 +1469,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { StorageManager.UUID_PRIVATE_INTERNAL, false, mDefaultPermissionCallback); for (final int userId : UserManagerService.getInstance().getUserIds()) { mPackageManagerInt.forEachPackage( - (PackageParser.Package pkg) -> resetRuntimePermissionsInternal(pkg, userId)); + (AndroidPackage pkg) -> resetRuntimePermissionsInternal(pkg, userId)); } } @@ -1471,9 +1480,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param userId The device user for which to do a reset. */ @GuardedBy("mLock") - private void resetRuntimePermissionsInternal(final PackageParser.Package pkg, + private void resetRuntimePermissionsInternal(final AndroidPackage pkg, final int userId) { - final String packageName = pkg.packageName; + final String packageName = pkg.getPackageName(); // These are flags that can change base on user actions. final int userSettableMask = FLAG_PERMISSION_USER_SET @@ -1485,7 +1494,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { | FLAG_PERMISSION_POLICY_FIXED; // Delay and combine non-async permission callbacks - final int permissionCount = pkg.requestedPermissions.size(); + final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions()); final boolean[] permissionRemoved = new boolean[1]; final ArraySet<Long> revokedPermissions = new ArraySet<>(); final IntArray syncUpdatedUsers = new IntArray(permissionCount); @@ -1552,7 +1561,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { }; for (int i = 0; i < permissionCount; i++) { - final String permName = pkg.requestedPermissions.get(i); + final String permName = pkg.getRequestedPermissions().get(i); final BasePermission bp; synchronized (mLock) { bp = mSettings.getPermissionLocked(permName); @@ -1567,7 +1576,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // If shared user we just reset the state to which only this app contributed. final String sharedUserId = - mPackageManagerInt.getSharedUserIdForPackage(pkg.packageName); + mPackageManagerInt.getSharedUserIdForPackage(pkg.getPackageName()); final String[] pkgNames = mPackageManagerInt.getPackagesForSharedUserId(sharedUserId, userId); if (pkgNames != null && pkgNames.length > 0) { @@ -1575,10 +1584,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int packageCount = pkgNames.length; for (int j = 0; j < packageCount; j++) { final String sharedPkgName = pkgNames[j]; - final PackageParser.Package sharedPkg = + final AndroidPackage sharedPkg = mPackageManagerInt.getPackage(sharedPkgName); - if (sharedPkg != null && !sharedPkg.packageName.equals(packageName) - && sharedPkg.requestedPermissions.contains(permName)) { + if (sharedPkg != null && !sharedPkg.getPackageName().equals(packageName) + && sharedPkg.getRequestedPermissions().contains(permName)) { used = true; break; } @@ -1999,15 +2008,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { return protectionLevel; } // Normalize package name to handle renamed packages and static libs - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); if (pkg == null) { return protectionLevel; } - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) { + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) { return protectionLevelMasked; } // Apps that target O see flags for all protection levels. - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); if (ps == null) { return protectionLevel; } @@ -2028,35 +2038,35 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param permissionCallback Callback for permission changed */ private void revokeRuntimePermissionsIfGroupChanged( - @NonNull PackageParser.Package newPackage, - @NonNull PackageParser.Package oldPackage, + @NonNull AndroidPackage newPackage, + @NonNull AndroidPackage oldPackage, @NonNull ArrayList<String> allPackageNames, @NonNull PermissionCallback permissionCallback) { - final int numOldPackagePermissions = oldPackage.permissions.size(); + final int numOldPackagePermissions = ArrayUtils.size(oldPackage.getPermissions()); final ArrayMap<String, String> oldPermissionNameToGroupName = new ArrayMap<>(numOldPackagePermissions); for (int i = 0; i < numOldPackagePermissions; i++) { - final PackageParser.Permission permission = oldPackage.permissions.get(i); + final ParsedPermission permission = oldPackage.getPermissions().get(i); - if (permission.group != null) { - oldPermissionNameToGroupName.put(permission.info.name, - permission.group.info.name); + if (permission.parsedPermissionGroup != null) { + oldPermissionNameToGroupName.put(permission.getName(), + permission.parsedPermissionGroup.getName()); } } final int callingUid = Binder.getCallingUid(); - final int numNewPackagePermissions = newPackage.permissions.size(); + final int numNewPackagePermissions = ArrayUtils.size(newPackage.getPermissions()); for (int newPermissionNum = 0; newPermissionNum < numNewPackagePermissions; newPermissionNum++) { - final PackageParser.Permission newPermission = - newPackage.permissions.get(newPermissionNum); - final int newProtection = newPermission.info.getProtection(); + final ParsedPermission newPermission = + newPackage.getPermissions().get(newPermissionNum); + final int newProtection = newPermission.getProtection(); if ((newProtection & PermissionInfo.PROTECTION_DANGEROUS) != 0) { - final String permissionName = newPermission.info.name; - final String newPermissionGroupName = - newPermission.group == null ? null : newPermission.group.info.name; + final String permissionName = newPermission.getName(); + final String newPermissionGroupName = newPermission.parsedPermissionGroup == null + ? null : newPermission.parsedPermissionGroup.getName(); final String oldPermissionGroupName = oldPermissionNameToGroupName.get( permissionName); @@ -2074,7 +2084,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { userId); if (permissionState == PackageManager.PERMISSION_GRANTED) { EventLog.writeEvent(0x534e4554, "72710897", - newPackage.applicationInfo.uid, + newPackage.getUid(), "Revoking permission " + permissionName + " from package " + packageName + " as the group changed from " + oldPermissionGroupName + @@ -2095,54 +2105,56 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - private void addAllPermissions(PackageParser.Package pkg, boolean chatty) { - final int N = pkg.permissions.size(); + private void addAllPermissions(AndroidPackage pkg, boolean chatty) { + final int N = ArrayUtils.size(pkg.getPermissions()); for (int i=0; i<N; i++) { - PackageParser.Permission p = pkg.permissions.get(i); + ParsedPermission p = pkg.getPermissions().get(i); // Assume by default that we did not install this permission into the system. - p.info.flags &= ~PermissionInfo.FLAG_INSTALLED; + p.flags &= ~PermissionInfo.FLAG_INSTALLED; synchronized (PermissionManagerService.this.mLock) { // Now that permission groups have a special meaning, we ignore permission // groups for legacy apps to prevent unexpected behavior. In particular, // permissions for one app being granted to someone just because they happen // to be in a group defined by another app (before this had no implications). - if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { - p.group = mSettings.mPermissionGroups.get(p.info.group); + if (pkg.getTargetSdkVersion() > Build.VERSION_CODES.LOLLIPOP_MR1) { + p.parsedPermissionGroup = mSettings.mPermissionGroups.get(p.getGroup()); // Warn for a permission in an unknown group. if (DEBUG_PERMISSIONS - && p.info.group != null && p.group == null) { - Slog.i(TAG, "Permission " + p.info.name + " from package " - + p.info.packageName + " in an unknown group " + p.info.group); + && p.getGroup() != null && p.parsedPermissionGroup == null) { + Slog.i(TAG, "Permission " + p.getName() + " from package " + + p.getPackageName() + " in an unknown group " + p.getGroup()); } } if (p.tree) { final BasePermission bp = BasePermission.createOrUpdate( - mSettings.getPermissionTreeLocked(p.info.name), p, pkg, + mPackageManagerInt, + mSettings.getPermissionTreeLocked(p.getName()), p, pkg, mSettings.getAllPermissionTreesLocked(), chatty); - mSettings.putPermissionTreeLocked(p.info.name, bp); + mSettings.putPermissionTreeLocked(p.getName(), bp); } else { final BasePermission bp = BasePermission.createOrUpdate( - mSettings.getPermissionLocked(p.info.name), + mPackageManagerInt, + mSettings.getPermissionLocked(p.getName()), p, pkg, mSettings.getAllPermissionTreesLocked(), chatty); - mSettings.putPermissionLocked(p.info.name, bp); + mSettings.putPermissionLocked(p.getName(), bp); } } } } - private void addAllPermissionGroups(PackageParser.Package pkg, boolean chatty) { - final int N = pkg.permissionGroups.size(); + private void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) { + final int N = ArrayUtils.size(pkg.getPermissionGroups()); StringBuilder r = null; for (int i=0; i<N; i++) { - final PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i); - final PackageParser.PermissionGroup cur = mSettings.mPermissionGroups.get(pg.info.name); - final String curPackageName = (cur == null) ? null : cur.info.packageName; - final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName); + final ParsedPermissionGroup pg = pkg.getPermissionGroups().get(i); + final ParsedPermissionGroup cur = mSettings.mPermissionGroups.get(pg.getName()); + final String curPackageName = (cur == null) ? null : cur.getPackageName(); + final boolean isPackageUpdate = pg.getPackageName().equals(curPackageName); if (cur == null || isPackageUpdate) { - mSettings.mPermissionGroups.put(pg.info.name, pg); + mSettings.mPermissionGroups.put(pg.getName(), pg); if (chatty && DEBUG_PACKAGE_SCANNING) { if (r == null) { r = new StringBuilder(256); @@ -2152,12 +2164,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (isPackageUpdate) { r.append("UPD:"); } - r.append(pg.info.name); + r.append(pg.getName()); } } else { - Slog.w(TAG, "Permission group " + pg.info.name + " from package " - + pg.info.packageName + " ignored: original from " - + cur.info.packageName); + Slog.w(TAG, "Permission group " + pg.getName() + " from package " + + pg.getPackageName() + " ignored: original from " + + cur.getPackageName()); if (chatty && DEBUG_PACKAGE_SCANNING) { if (r == null) { r = new StringBuilder(256); @@ -2165,7 +2177,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { r.append(' '); } r.append("DUP:"); - r.append(pg.info.name); + r.append(pg.getName()); } } } @@ -2175,15 +2187,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { } - private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) { + private void removeAllPermissions(AndroidPackage pkg, boolean chatty) { synchronized (mLock) { - int N = pkg.permissions.size(); + int N = ArrayUtils.size(pkg.getPermissions()); StringBuilder r = null; for (int i=0; i<N; i++) { - PackageParser.Permission p = pkg.permissions.get(i); - BasePermission bp = (BasePermission) mSettings.mPermissions.get(p.info.name); + ParsedPermission p = pkg.getPermissions().get(i); + BasePermission bp = mSettings.mPermissions.get(p.getName()); if (bp == null) { - bp = mSettings.mPermissionTrees.get(p.info.name); + bp = mSettings.mPermissionTrees.get(p.getName()); } if (bp != null && bp.isPermission(p)) { bp.setPermission(null); @@ -2193,14 +2205,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { } else { r.append(' '); } - r.append(p.info.name); + r.append(p.getName()); } } if (p.isAppOp()) { ArraySet<String> appOpPkgs = - mSettings.mAppOpPermissionPackages.get(p.info.name); + mSettings.mAppOpPermissionPackages.get(p.getName()); if (appOpPkgs != null) { - appOpPkgs.remove(pkg.packageName); + appOpPkgs.remove(pkg.getPackageName()); } } } @@ -2208,14 +2220,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); } - N = pkg.requestedPermissions.size(); + N = pkg.getRequestedPermissions().size(); r = null; for (int i=0; i<N; i++) { - String perm = pkg.requestedPermissions.get(i); + String perm = pkg.getRequestedPermissions().get(i); if (mSettings.isPermissionAppOp(perm)) { ArraySet<String> appOpPkgs = mSettings.mAppOpPermissionPackages.get(perm); if (appOpPkgs != null) { - appOpPkgs.remove(pkg.packageName); + appOpPkgs.remove(pkg.getPackageName()); if (appOpPkgs.isEmpty()) { mSettings.mAppOpPermissionPackages.remove(perm); } @@ -2244,7 +2256,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param packageOfInterest If this is the name of {@code pkg} add extra logging * @param callback Result call back */ - private void restorePermissionState(@NonNull PackageParser.Package pkg, boolean replace, + private void restorePermissionState(@NonNull AndroidPackage pkg, boolean replace, @Nullable String packageOfInterest, @Nullable PermissionCallback callback) { // IMPORTANT: There are two types of permissions: install and runtime. // Install time permissions are granted when the app is installed to @@ -2257,7 +2269,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { // being upgraded to target a newer SDK, in which case dangerous permissions // are transformed from install time to runtime ones. - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); if (ps == null) { return; } @@ -2298,23 +2311,25 @@ public class PermissionManagerService extends IPermissionManager.Stub { synchronized (mLock) { ArraySet<String> newImplicitPermissions = new ArraySet<>(); - final int N = pkg.requestedPermissions.size(); + final int N = pkg.getRequestedPermissions().size(); for (int i = 0; i < N; i++) { - final String permName = pkg.requestedPermissions.get(i); + final String permName = pkg.getRequestedPermissions().get(i); final BasePermission bp = mSettings.getPermissionLocked(permName); final boolean appSupportsRuntimePermissions = - pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M; + pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M; String upgradedActivityRecognitionPermission = null; if (DEBUG_INSTALL) { - Log.i(TAG, "Package " + pkg.packageName + " checking " + permName + ": " + bp); + Log.i(TAG, "Package " + pkg.getPackageName() + + " checking " + permName + ": " + bp); } if (bp == null || bp.getSourcePackageSetting() == null) { - if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) { + if (packageOfInterest == null || packageOfInterest.equals( + pkg.getPackageName())) { if (DEBUG_PERMISSIONS) { Slog.i(TAG, "Unknown permission " + permName - + " in package " + pkg.packageName); + + " in package " + pkg.getPackageName()); } } continue; @@ -2323,14 +2338,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Cache newImplicitPermissions before modifing permissionsState as for the shared // uids the original and new state are the same object if (!origPermissions.hasRequestedPermission(permName) - && (pkg.implicitPermissions.contains(permName) + && (pkg.getImplicitPermissions().contains(permName) || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) { - if (pkg.implicitPermissions.contains(permName)) { + if (pkg.getImplicitPermissions().contains(permName)) { // If permName is an implicit permission, try to auto-grant newImplicitPermissions.add(permName); if (DEBUG_PERMISSIONS) { - Slog.i(TAG, permName + " is newly added for " + pkg.packageName); + Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName()); } } else { // Special case for Activity Recognition permission. Even if AR permission @@ -2353,7 +2368,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (DEBUG_PERMISSIONS) { Slog.i(TAG, permName + " is newly added for " - + pkg.packageName); + + pkg.getPackageName()); } break; } @@ -2362,10 +2377,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { } // Limit ephemeral apps to ephemeral allowed permissions. - if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) { + if (pkg.isInstantApp() && !bp.isInstant()) { if (DEBUG_PERMISSIONS) { Log.i(TAG, "Denying non-ephemeral permission " + bp.getName() - + " for package " + pkg.packageName); + + " for package " + pkg.getPackageName()); } continue; } @@ -2373,7 +2388,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) { if (DEBUG_PERMISSIONS) { Log.i(TAG, "Denying runtime-only permission " + bp.getName() - + " for package " + pkg.packageName); + + " for package " + pkg.getPackageName()); } continue; } @@ -2384,7 +2399,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Keep track of app op permissions. if (bp.isAppOp()) { - mSettings.addAppOpPackage(perm, pkg.packageName); + mSettings.addAppOpPackage(perm, pkg.getPackageName()); } if (bp.isNormal()) { @@ -2410,7 +2425,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (DEBUG_PERMISSIONS) { Slog.i(TAG, "Considering granting permission " + perm + " to package " - + pkg.packageName); + + pkg.getPackageName()); } if (grant != GRANT_DENIED) { @@ -2696,10 +2711,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { default: { if (packageOfInterest == null - || packageOfInterest.equals(pkg.packageName)) { + || packageOfInterest.equals(pkg.getPackageName())) { if (DEBUG_PERMISSIONS) { Slog.i(TAG, "Not granting permission " + perm - + " to package " + pkg.packageName + + " to package " + pkg.getPackageName() + " because it was previously installed without"); } } @@ -2714,9 +2729,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { changedInstallPermission = true; if (DEBUG_PERMISSIONS) { Slog.i(TAG, "Un-granting permission " + perm - + " from package " + pkg.packageName + + " from package " + pkg.getPackageName() + " (protectionLevel=" + bp.getProtectionLevel() - + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) + + " flags=0x" + Integer.toHexString(pkg.getFlags()) + ")"); } } else if (bp.isAppOp()) { @@ -2724,11 +2739,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { // not to be granted, there is a UI for the user to decide. if (DEBUG_PERMISSIONS && (packageOfInterest == null - || packageOfInterest.equals(pkg.packageName))) { + || packageOfInterest.equals(pkg.getPackageName()))) { Slog.i(TAG, "Not granting permission " + perm - + " to package " + pkg.packageName + + " to package " + pkg.getPackageName() + " (protectionLevel=" + bp.getProtectionLevel() - + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) + + " flags=0x" + Integer.toHexString(pkg.getFlags()) + ")"); } } @@ -2758,7 +2773,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } for (int userId : updatedUserIds) { - notifyRuntimePermissionStateChanged(pkg.packageName, userId); + notifyRuntimePermissionStateChanged(pkg.getPackageName(), userId); } } @@ -2774,10 +2789,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @return The updated value of the {@code updatedUserIds} parameter */ private @NonNull int[] revokePermissionsNoLongerImplicitLocked( - @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg, + @NonNull PermissionsState ps, @NonNull AndroidPackage pkg, @NonNull int[] updatedUserIds) { - String pkgName = pkg.packageName; - boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion + String pkgName = pkg.getPackageName(); + boolean supportsRuntimePermissions = pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M; int[] users = UserManagerService.getInstance().getUserIds(); @@ -2786,7 +2801,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { int userId = users[i]; for (String permission : ps.getPermissions(userId)) { - if (!pkg.implicitPermissions.contains(permission)) { + if (!pkg.getImplicitPermissions().contains(permission)) { if (!ps.hasInstallPermission(permission)) { int flags = ps.getRuntimePermissionState(permission, userId).getFlags(); @@ -2836,9 +2851,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { */ private void inheritPermissionStateToNewImplicitPermissionLocked( @NonNull ArraySet<String> sourcePerms, @NonNull String newPerm, - @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg, + @NonNull PermissionsState ps, @NonNull AndroidPackage pkg, @UserIdInt int userId) { - String pkgName = pkg.packageName; + String pkgName = pkg.getPackageName(); boolean isGranted = false; int flags = 0; @@ -2885,10 +2900,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @return The ids of the users that are changed */ private @NonNull int[] checkIfLegacyStorageOpsNeedToBeUpdated( - @NonNull PackageParser.Package pkg, boolean replace, @NonNull int[] updatedUserIds) { - if (replace && pkg.applicationInfo.hasRequestedLegacyExternalStorage() && ( - pkg.requestedPermissions.contains(READ_EXTERNAL_STORAGE) - || pkg.requestedPermissions.contains(WRITE_EXTERNAL_STORAGE))) { + @NonNull AndroidPackage pkg, boolean replace, @NonNull int[] updatedUserIds) { + if (replace && pkg.hasRequestedLegacyExternalStorage() && ( + pkg.getRequestedPermissions().contains(READ_EXTERNAL_STORAGE) + || pkg.getRequestedPermissions().contains(WRITE_EXTERNAL_STORAGE))) { return UserManagerService.getInstance().getUserIds(); } @@ -2907,10 +2922,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { */ private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked( @NonNull PermissionsState origPs, - @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg, + @NonNull PermissionsState ps, @NonNull AndroidPackage pkg, @NonNull ArraySet<String> newImplicitPermissions, @NonNull int[] updatedUserIds) { - String pkgName = pkg.packageName; + String pkgName = pkg.getPackageName(); ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>(); final List<SplitPermissionInfoParcelable> permissionList = getSplitPermissions(); @@ -2990,17 +3005,17 @@ public class PermissionManagerService extends IPermissionManager.Stub { SystemConfig.getInstance().getSplitPermissions()); } - private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) { + private boolean isNewPlatformPermissionForPackage(String perm, AndroidPackage pkg) { boolean allowed = false; final int NP = PackageParser.NEW_PERMISSIONS.length; for (int ip=0; ip<NP; ip++) { final PackageParser.NewPermissionInfo npi = PackageParser.NEW_PERMISSIONS[ip]; if (npi.name.equals(perm) - && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) { + && pkg.getTargetSdkVersion() < npi.sdkVersion) { allowed = true; Log.i(TAG, "Auto-granting " + perm + " to old pkg " - + pkg.packageName); + + pkg.getPackageName()); break; } } @@ -3014,29 +3029,26 @@ public class PermissionManagerService extends IPermissionManager.Stub { * * <p>This handles parent/child apps. */ - private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) { - ArraySet<String> wlPermissions = null; + private boolean hasPrivappWhitelistEntry(String perm, AndroidPackage pkg) { + ArraySet<String> wlPermissions; if (pkg.isVendor()) { wlPermissions = - SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName); + SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.getPackageName()); } else if (pkg.isProduct()) { wlPermissions = - SystemConfig.getInstance().getProductPrivAppPermissions(pkg.packageName); + SystemConfig.getInstance().getProductPrivAppPermissions(pkg.getPackageName()); } else if (pkg.isSystemExt()) { wlPermissions = SystemConfig.getInstance().getSystemExtPrivAppPermissions( - pkg.packageName); + pkg.getPackageName()); } else { - wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName); + wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.getPackageName()); } - // Let's check if this package is whitelisted... - boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm); - // If it's not, we'll also tail-recurse to the parent. - return whitelisted || - pkg.parentPackage != null && hasPrivappWhitelistEntry(perm, pkg.parentPackage); + + return wlPermissions != null && wlPermissions.contains(perm); } - private boolean grantSignaturePermission(String perm, PackageParser.Package pkg, + private boolean grantSignaturePermission(String perm, AndroidPackage pkg, BasePermission bp, PermissionsState origPermissions) { boolean oemPermission = bp.isOEM(); boolean vendorPrivilegedPermission = bp.isVendorPrivileged(); @@ -3044,7 +3056,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { boolean privappPermissionsDisable = RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE; boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName()); - boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName); + boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName()); if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged() && !platformPackage && platformPermission) { if (!hasPrivappWhitelistEntry(perm, pkg)) { @@ -3054,22 +3066,22 @@ public class PermissionManagerService extends IPermissionManager.Stub { ArraySet<String> deniedPermissions = null; if (pkg.isVendor()) { deniedPermissions = SystemConfig.getInstance() - .getVendorPrivAppDenyPermissions(pkg.packageName); + .getVendorPrivAppDenyPermissions(pkg.getPackageName()); } else if (pkg.isProduct()) { deniedPermissions = SystemConfig.getInstance() - .getProductPrivAppDenyPermissions(pkg.packageName); + .getProductPrivAppDenyPermissions(pkg.getPackageName()); } else if (pkg.isSystemExt()) { deniedPermissions = SystemConfig.getInstance() - .getSystemExtPrivAppDenyPermissions(pkg.packageName); + .getSystemExtPrivAppDenyPermissions(pkg.getPackageName()); } else { deniedPermissions = SystemConfig.getInstance() - .getPrivAppDenyPermissions(pkg.packageName); + .getPrivAppDenyPermissions(pkg.getPackageName()); } final boolean permissionViolation = deniedPermissions == null || !deniedPermissions.contains(perm); if (permissionViolation) { Slog.w(TAG, "Privileged permission " + perm + " for package " - + pkg.packageName + " (" + pkg.codePath + + pkg.getPackageName() + " (" + pkg.getCodePath() + ") not in privapp-permissions whitelist"); if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) { @@ -3077,7 +3089,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { mPrivappPermissionsViolations = new ArraySet<>(); } mPrivappPermissionsViolations.add( - pkg.packageName + " (" + pkg.codePath + "): " + perm); + pkg.getPackageName() + " (" + pkg.getCodePath() + "): " + perm); } } else { return false; @@ -3091,7 +3103,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // expect single system package String systemPackageName = ArrayUtils.firstOrNull(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM)); - final PackageParser.Package systemPackage = + final AndroidPackage systemPackage = mPackageManagerInt.getPackage(systemPackageName); // check if the package is allow to use this signature permission. A package is allowed to @@ -3102,24 +3114,23 @@ public class PermissionManagerService extends IPermissionManager.Stub { // package, and the defining package still trusts the old certificate for permissions // - or it shares the above relationships with the system package boolean allowed = - pkg.mSigningDetails.hasAncestorOrSelf( + pkg.getSigningDetails().hasAncestorOrSelf( bp.getSourcePackageSetting().getSigningDetails()) || bp.getSourcePackageSetting().getSigningDetails().checkCapability( - pkg.mSigningDetails, + pkg.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.PERMISSION) - || pkg.mSigningDetails.hasAncestorOrSelf(systemPackage.mSigningDetails) - || systemPackage.mSigningDetails.checkCapability( - pkg.mSigningDetails, + || pkg.getSigningDetails().hasAncestorOrSelf(systemPackage.getSigningDetails()) + || systemPackage.getSigningDetails().checkCapability( + pkg.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.PERMISSION); if (!allowed && (privilegedPermission || oemPermission)) { if (pkg.isSystem()) { // For updated system applications, a privileged/oem permission // is granted only if it had been defined by the original application. if (pkg.isUpdatedSystemApp()) { - final PackageParser.Package disabledPkg = - mPackageManagerInt.getDisabledSystemPackage(pkg.packageName); - final PackageSetting disabledPs = - (disabledPkg != null) ? (PackageSetting) disabledPkg.mExtras : null; + final PackageSetting disabledPs = (PackageSetting) mPackageManagerInt + .getDisabledSystemPackage(pkg.getPackageName()); + final AndroidPackage disabledPkg = disabledPs == null ? null : disabledPs.pkg; if (disabledPs != null && disabledPs.getPermissionsState().hasInstallPermission(perm)) { // If the original was granted this permission, we take @@ -3144,40 +3155,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { && canGrantOemPermission(disabledPs, perm)))) { allowed = true; } - // Also if a privileged parent package on the system image or any of - // its children requested a privileged/oem permission, the updated child - // packages can also get the permission. - if (pkg.parentPackage != null) { - final PackageParser.Package disabledParentPkg = mPackageManagerInt - .getDisabledSystemPackage(pkg.parentPackage.packageName); - final PackageSetting disabledParentPs = (disabledParentPkg != null) - ? (PackageSetting) disabledParentPkg.mExtras : null; - if (disabledParentPkg != null - && ((privilegedPermission && disabledParentPs.isPrivileged()) - || (oemPermission && disabledParentPs.isOem()))) { - if (isPackageRequestingPermission(disabledParentPkg, perm) - && canGrantOemPermission(disabledParentPs, perm)) { - allowed = true; - } else if (disabledParentPkg.childPackages != null) { - for (PackageParser.Package disabledChildPkg - : disabledParentPkg.childPackages) { - final PackageSetting disabledChildPs = - (disabledChildPkg != null) - ? (PackageSetting) disabledChildPkg.mExtras - : null; - if (isPackageRequestingPermission(disabledChildPkg, perm) - && canGrantOemPermission( - disabledChildPs, perm)) { - allowed = true; - break; - } - } - } - } - } } } else { - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); allowed = (privilegedPermission && pkg.isPrivileged()) || (oemPermission && pkg.isOem() && canGrantOemPermission(ps, perm)); @@ -3188,7 +3169,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (allowed && privilegedPermission && !vendorPrivilegedPermission && pkg.isVendor()) { Slog.w(TAG, "Permission " + perm + " cannot be granted to privileged vendor apk " - + pkg.packageName + " because it isn't a 'vendorPrivileged' permission."); + + pkg.getPackageName() + + " because it isn't a 'vendorPrivileged' permission."); allowed = false; } } @@ -3196,7 +3178,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (!allowed) { if (!allowed && bp.isPre23() - && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { + && pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) { // If this was a previously normal/dangerous permission that got moved // to a system permission as part of the runtime permission redesign, then // we still want to blindly grant it to old apps. @@ -3208,9 +3190,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (!allowed && bp.isInstaller() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM), - pkg.packageName) || ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER, - UserHandle.USER_SYSTEM), pkg.packageName)) { + pkg.getPackageName()) || ArrayUtils.contains( + mPackageManagerInt.getKnownPackageNames( + PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER, + UserHandle.USER_SYSTEM), pkg.getPackageName())) { // If this permission is to be granted to the system installer and // this app is an installer, then it gets the permission. allowed = true; @@ -3218,7 +3201,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (!allowed && bp.isVerifier() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM), - pkg.packageName)) { + pkg.getPackageName())) { // If this permission is to be granted to the system verifier and // this app is a verifier, then it gets the permission. allowed = true; @@ -3236,7 +3219,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (!allowed && bp.isSetup() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM), - pkg.packageName)) { + pkg.getPackageName())) { // If this permission is to be granted to the system setup wizard and // this app is a setup wizard, then it gets the permission. allowed = true; @@ -3244,28 +3227,28 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (!allowed && bp.isSystemTextClassifier() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER, - UserHandle.USER_SYSTEM), pkg.packageName)) { + UserHandle.USER_SYSTEM), pkg.getPackageName())) { // Special permissions for the system default text classifier. allowed = true; } if (!allowed && bp.isConfigurator() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_CONFIGURATOR, - UserHandle.USER_SYSTEM), pkg.packageName)) { + UserHandle.USER_SYSTEM), pkg.getPackageName())) { // Special permissions for the device configurator. allowed = true; } if (!allowed && bp.isWellbeing() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM), - pkg.packageName)) { + pkg.getPackageName())) { // Special permission granted only to the OEM specified wellbeing app allowed = true; } if (!allowed && bp.isDocumenter() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_DOCUMENTER, UserHandle.USER_SYSTEM), - pkg.packageName)) { + pkg.getPackageName())) { // If this permission is to be granted to the documenter and // this app is the documenter, then it gets the permission. allowed = true; @@ -3273,7 +3256,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (!allowed && bp.isIncidentReportApprover() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER, - UserHandle.USER_SYSTEM), pkg.packageName)) { + UserHandle.USER_SYSTEM), pkg.getPackageName())) { // If this permission is to be granted to the incident report approver and // this app is the incident report approver, then it gets the permission. allowed = true; @@ -3281,14 +3264,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (!allowed && bp.isAppPredictor() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM), - pkg.packageName)) { + pkg.getPackageName())) { // Special permissions for the system app predictor. allowed = true; } if (!allowed && bp.isTelephony() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_TELEPHONY, UserHandle.USER_SYSTEM), - pkg.packageName)) { + pkg.getPackageName())) { // Special permissions for the system telephony apps. allowed = true; } @@ -3310,26 +3293,27 @@ public class PermissionManagerService extends IPermissionManager.Stub { return Boolean.TRUE == granted; } - private boolean isPermissionsReviewRequired(@NonNull PackageParser.Package pkg, + private boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg, @UserIdInt int userId) { // Permission review applies only to apps not supporting the new permission model. - if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) { + if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M) { return false; } // Legacy apps have the permission and get user consent on launch. - if (pkg.mExtras == null) { + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); + if (ps == null) { return false; } - final PackageSetting ps = (PackageSetting) pkg.mExtras; final PermissionsState permissionsState = ps.getPermissionsState(); return permissionsState.isPermissionReviewRequired(userId); } - private boolean isPackageRequestingPermission(PackageParser.Package pkg, String permission) { - final int permCount = pkg.requestedPermissions.size(); + private boolean isPackageRequestingPermission(AndroidPackage pkg, String permission) { + final int permCount = pkg.getRequestedPermissions().size(); for (int j = 0; j < permCount; j++) { - String requestedPermission = pkg.requestedPermissions.get(j); + String requestedPermission = pkg.getRequestedPermissions().get(j); if (permission.equals(requestedPermission)) { return true; } @@ -3337,41 +3321,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { return false; } - @GuardedBy("mLock") - private void grantRuntimePermissionsGrantedToDisabledPackageLocked( - PackageParser.Package pkg, int callingUid, PermissionCallback callback) { - if (pkg.parentPackage == null) { - return; - } - if (pkg.requestedPermissions == null) { - return; - } - final PackageParser.Package disabledPkg = - mPackageManagerInt.getDisabledSystemPackage(pkg.parentPackage.packageName); - if (disabledPkg == null || disabledPkg.mExtras == null) { - return; - } - final PackageSetting disabledPs = (PackageSetting) disabledPkg.mExtras; - if (!disabledPs.isPrivileged() || disabledPs.hasChildPackages()) { - return; - } - final int permCount = pkg.requestedPermissions.size(); - for (int i = 0; i < permCount; i++) { - String permission = pkg.requestedPermissions.get(i); - BasePermission bp = mSettings.getPermissionLocked(permission); - if (bp == null || !(bp.isRuntime() || bp.isDevelopment())) { - continue; - } - for (int userId : mUserManagerInt.getUserIds()) { - if (disabledPs.getPermissionsState().hasRuntimePermission(permission, userId)) { - grantRuntimePermissionInternal( - permission, pkg.packageName, false, callingUid, userId, callback); - } - } - } - } - - private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds, + private void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds, String[] grantedPermissions, int callingUid, PermissionCallback callback) { for (int userId : userIds) { grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions, callingUid, @@ -3379,9 +3329,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId, + private void grantRequestedRuntimePermissionsForUser(AndroidPackage pkg, int userId, String[] grantedPermissions, int callingUid, PermissionCallback callback) { - PackageSetting ps = (PackageSetting) pkg.mExtras; + PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); if (ps == null) { return; } @@ -3394,12 +3345,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int compatFlags = PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT; - final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion + final boolean supportsRuntimePermissions = pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M; - final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.packageName, userId); + final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.getPackageName(), userId); - for (String permission : pkg.requestedPermissions) { + for (String permission : pkg.getRequestedPermissions()) { final BasePermission bp; synchronized (mLock) { bp = mSettings.getPermissionLocked(permission); @@ -3413,14 +3364,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (supportsRuntimePermissions) { // Installer cannot change immutable permissions. if ((flags & immutableFlags) == 0) { - grantRuntimePermissionInternal(permission, pkg.packageName, false, + grantRuntimePermissionInternal(permission, pkg.getPackageName(), false, callingUid, userId, callback); } } else { // In permission review mode we clear the review flag and the revoked compat // flag when we are asked to install the app with all permissions granted. if ((flags & compatFlags) != 0) { - updatePermissionFlagsInternal(permission, pkg.packageName, compatFlags, + updatePermissionFlagsInternal(permission, pkg.getPackageName(), compatFlags, 0, callingUid, userId, false, callback); } } @@ -3428,11 +3379,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - private void setWhitelistedRestrictedPermissionsForUser(@NonNull PackageParser.Package pkg, + private void setWhitelistedRestrictedPermissionsForUser(@NonNull AndroidPackage pkg, @UserIdInt int userId, @Nullable List<String> permissions, int callingUid, @PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) { final PermissionsState permissionsState = - PackageManagerServiceUtils.getPermissionsState(pkg); + PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg); if (permissionsState == null) { return; } @@ -3440,9 +3391,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { ArraySet<String> oldGrantedRestrictedPermissions = null; boolean updatePermissions = false; - final int permissionCount = pkg.requestedPermissions.size(); + final int permissionCount = pkg.getRequestedPermissions().size(); for (int i = 0; i < permissionCount; i++) { - final String permissionName = pkg.requestedPermissions.get(i); + final String permissionName = pkg.getRequestedPermissions().get(i); final BasePermission bp = mSettings.getPermissionLocked(permissionName); @@ -3518,19 +3469,19 @@ public class PermissionManagerService extends IPermissionManager.Stub { // If we are whitelisting an app that does not support runtime permissions // we need to make sure it goes through the permission review UI at launch. - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && !wasWhitelisted && isWhitelisted) { mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; } - updatePermissionFlagsInternal(permissionName, pkg.packageName, mask, newFlags, + updatePermissionFlagsInternal(permissionName, pkg.getPackageName(), mask, newFlags, callingUid, userId, false, null /*callback*/); } if (updatePermissions) { // Update permission of this app to take into account the new whitelist state. - restorePermissionState(pkg, false, pkg.packageName, callback); + restorePermissionState(pkg, false, pkg.getPackageName(), callback); // If this resulted in losing a permission we need to kill the app. if (oldGrantedRestrictedPermissions != null) { @@ -3539,9 +3490,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { final String permission = oldGrantedRestrictedPermissions.valueAt(i); // Sometimes we create a new permission state instance during update. final PermissionsState newPermissionsState = - PackageManagerServiceUtils.getPermissionsState(pkg); + PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg); if (!newPermissionsState.hasPermission(permission, userId)) { - callback.onPermissionRevoked(pkg.applicationInfo.uid, userId); + callback.onPermissionRevoked(pkg.getUid(), userId); break; } } @@ -3554,17 +3505,17 @@ public class PermissionManagerService extends IPermissionManager.Stub { SharedUserSetting suSetting, int[] allUserIds) { // Collect all used permissions in the UID final ArraySet<String> usedPermissions = new ArraySet<>(); - final List<PackageParser.Package> pkgList = suSetting.getPackages(); + final List<AndroidPackage> pkgList = suSetting.getPackages(); if (pkgList == null || pkgList.size() == 0) { return EmptyArray.INT; } - for (PackageParser.Package pkg : pkgList) { - if (pkg.requestedPermissions == null) { + for (AndroidPackage pkg : pkgList) { + if (pkg.getRequestedPermissions() == null) { continue; } - final int requestedPermCount = pkg.requestedPermissions.size(); + final int requestedPermCount = pkg.getRequestedPermissions().size(); for (int j = 0; j < requestedPermCount; j++) { - String permission = pkg.requestedPermissions.get(j); + String permission = pkg.getRequestedPermissions().get(j); BasePermission bp = mSettings.getPermissionLocked(permission); if (bp != null) { usedPermissions.add(permission); @@ -3626,18 +3577,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param allPackages All currently known packages * @param callback Callback to call after permission changes */ - private void updatePermissions(@NonNull String packageName, @Nullable PackageParser.Package pkg, + private void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg, @NonNull PermissionCallback callback) { final int flags = (pkg != null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG : 0); updatePermissions( packageName, pkg, getVolumeUuidForPackage(pkg), flags, callback); - if (pkg != null && pkg.childPackages != null) { - for (PackageParser.Package childPkg : pkg.childPackages) { - updatePermissions(childPkg.packageName, childPkg, - getVolumeUuidForPackage(childPkg), flags, callback); - } - } } /** @@ -3673,10 +3618,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Only system declares background permissions, hence mapping does never change. mBackgroundPermissions = new ArrayMap<>(); for (BasePermission bp : mSettings.getAllPermissionsLocked()) { - if (bp.perm != null && bp.perm.info != null - && bp.perm.info.backgroundPermission != null) { + if (bp.perm != null && bp.perm.backgroundPermission != null) { String fgPerm = bp.name; - String bgPerm = bp.perm.info.backgroundPermission; + String bgPerm = bp.perm.backgroundPermission; List<String> fgPerms = mBackgroundPermissions.get(bgPerm); if (fgPerms == null) { @@ -3737,7 +3681,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param callback Callback to call after permission changes */ private void updatePermissions(final @Nullable String changingPkgName, - final @Nullable PackageParser.Package changingPkg, + final @Nullable AndroidPackage changingPkg, final @Nullable String replaceVolumeUuid, @UpdatePermissionFlags int flags, final @Nullable PermissionCallback callback) { @@ -3770,7 +3714,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Now update the permissions for all packages. if ((flags & UPDATE_PERMISSIONS_ALL) != 0) { final boolean replaceAll = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0); - mPackageManagerInt.forEachPackage((Package pkg) -> { + mPackageManagerInt.forEachPackage((AndroidPackage pkg) -> { if (pkg == changingPkg) { return; } @@ -3809,7 +3753,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @return {@code true} if a permission source package might have changed */ private boolean updatePermissionSourcePackage(@Nullable String packageName, - @Nullable PackageParser.Package pkg, + @Nullable AndroidPackage pkg, final @Nullable PermissionCallback callback) { boolean changed = false; @@ -3832,8 +3776,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) { final int userId = userIds[userIdNum]; - mPackageManagerInt.forEachPackage((Package p) -> { - final String pName = p.packageName; + mPackageManagerInt.forEachPackage((AndroidPackage p) -> { + final String pName = p.getPackageName(); final ApplicationInfo appInfo = mPackageManagerInt.getApplicationInfo(pName, 0, Process.SYSTEM_UID, UserHandle.USER_SYSTEM); @@ -3878,11 +3822,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if (needsUpdate != null) { for (final BasePermission bp : needsUpdate) { - final PackageParser.Package sourcePkg = + final AndroidPackage sourcePkg = mPackageManagerInt.getPackage(bp.getSourcePackageName()); + final PackageSetting sourcePs = + (PackageSetting) mPackageManagerInt.getPackageSetting( + bp.getSourcePackageName()); synchronized (mLock) { - if (sourcePkg != null && sourcePkg.mExtras != null) { - final PackageSetting sourcePs = (PackageSetting) sourcePkg.mExtras; + if (sourcePkg != null && sourcePs != null) { if (bp.getSourcePackageSetting() == null) { bp.setSourcePackageSetting(sourcePs); } @@ -3915,7 +3861,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @return {@code true} if a permission tree ownership might have changed */ private boolean updatePermissionTreeSourcePackage(@Nullable String packageName, - @Nullable PackageParser.Package pkg) { + @Nullable AndroidPackage pkg) { boolean changed = false; Set<BasePermission> needsUpdate = null; @@ -3941,11 +3887,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if (needsUpdate != null) { for (final BasePermission bp : needsUpdate) { - final PackageParser.Package sourcePkg = + final AndroidPackage sourcePkg = mPackageManagerInt.getPackage(bp.getSourcePackageName()); + final PackageSetting sourcePs = + (PackageSetting) mPackageManagerInt.getPackageSetting( + bp.getSourcePackageName()); synchronized (mLock) { - if (sourcePkg != null && sourcePkg.mExtras != null) { - final PackageSetting sourcePs = (PackageSetting) sourcePkg.mExtras; + if (sourcePkg != null && sourcePs != null) { if (bp.getSourcePackageSetting() == null) { bp.setSourcePackageSetting(sourcePs); } @@ -4068,24 +4016,28 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - private static String getVolumeUuidForPackage(PackageParser.Package pkg) { + private static String getVolumeUuidForPackage(AndroidPackage pkg) { if (pkg == null) { return StorageManager.UUID_PRIVATE_INTERNAL; } if (pkg.isExternal()) { - if (TextUtils.isEmpty(pkg.volumeUuid)) { + if (TextUtils.isEmpty(pkg.getVolumeUuid())) { return StorageManager.UUID_PRIMARY_PHYSICAL; } else { - return pkg.volumeUuid; + return pkg.getVolumeUuid(); } } else { return StorageManager.UUID_PRIVATE_INTERNAL; } } - private static boolean hasPermission(PackageParser.Package pkgInfo, String permName) { - for (int i=pkgInfo.permissions.size()-1; i>=0; i--) { - if (pkgInfo.permissions.get(i).info.name.equals(permName)) { + private static boolean hasPermission(AndroidPackage pkg, String permName) { + if (pkg.getPermissions() == null) { + return false; + } + + for (int i = pkg.getPermissions().size() - 1; i >= 0; i--) { + if (pkg.getPermissions().get(i).getName().equals(permName)) { return true; } } @@ -4124,37 +4076,39 @@ public class PermissionManagerService extends IPermissionManager.Stub { PermissionManagerService.this.systemReady(); } @Override - public boolean isPermissionsReviewRequired(@NonNull Package pkg, @UserIdInt int userId) { + public boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg, + @UserIdInt int userId) { return PermissionManagerService.this.isPermissionsReviewRequired(pkg, userId); } + @Override public void revokeRuntimePermissionsIfGroupChanged( - @NonNull PackageParser.Package newPackage, - @NonNull PackageParser.Package oldPackage, + @NonNull AndroidPackage newPackage, + @NonNull AndroidPackage oldPackage, @NonNull ArrayList<String> allPackageNames) { PermissionManagerService.this.revokeRuntimePermissionsIfGroupChanged(newPackage, oldPackage, allPackageNames, mDefaultPermissionCallback); } @Override - public void addAllPermissions(Package pkg, boolean chatty) { + public void addAllPermissions(AndroidPackage pkg, boolean chatty) { PermissionManagerService.this.addAllPermissions(pkg, chatty); } @Override - public void addAllPermissionGroups(Package pkg, boolean chatty) { + public void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) { PermissionManagerService.this.addAllPermissionGroups(pkg, chatty); } @Override - public void removeAllPermissions(Package pkg, boolean chatty) { + public void removeAllPermissions(AndroidPackage pkg, boolean chatty) { PermissionManagerService.this.removeAllPermissions(pkg, chatty); } @Override - public void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds, + public void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds, String[] grantedPermissions, int callingUid) { PermissionManagerService.this.grantRequestedRuntimePermissions( pkg, userIds, grantedPermissions, callingUid, mDefaultPermissionCallback); } @Override - public void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg, + public void setWhitelistedRestrictedPermissions(@NonNull AndroidPackage pkg, @NonNull int[] userIds, @Nullable List<String> permissions, int callingUid, @PackageManager.PermissionWhitelistFlags int flags) { for (int userId : userIds) { @@ -4169,13 +4123,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { packageName, permissions, flags, userId); } @Override - public void grantRuntimePermissionsGrantedToDisabledPackage(PackageParser.Package pkg, - int callingUid) { - PermissionManagerService.this.grantRuntimePermissionsGrantedToDisabledPackageLocked( - pkg, callingUid, mDefaultPermissionCallback); - } - @Override - public void updatePermissions(@NonNull String packageName, @Nullable Package pkg) { + public void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) { PermissionManagerService.this .updatePermissions(packageName, pkg, mDefaultPermissionCallback); } @@ -4185,13 +4133,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { .updateAllPermissions(volumeUuid, sdkUpdated, mDefaultPermissionCallback); } @Override - public void resetRuntimePermissions(Package pkg, int userId) { + public void resetRuntimePermissions(AndroidPackage pkg, int userId) { PermissionManagerService.this.resetRuntimePermissionsInternal(pkg, userId); } @Override public void resetAllRuntimePermissions(final int userId) { mPackageManagerInt.forEachPackage( - (PackageParser.Package pkg) -> resetRuntimePermissionsInternal(pkg, userId)); + (AndroidPackage pkg) -> resetRuntimePermissionsInternal(pkg, userId)); } @Override public String[] getAppOpPermissionPackages(String permName, int callingUid) { @@ -4237,9 +4185,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int i = 0; i < numTotalPermissions; i++) { BasePermission bp = mSettings.mPermissions.valueAt(i); - if (bp.perm != null && bp.perm.info != null - && bp.perm.info.getProtection() == protection) { - matchingPermissions.add(bp.perm.info); + if (bp.perm != null && bp.perm.getProtection() == protection) { + matchingPermissions.add( + PackageInfoUtils.generatePermissionInfo(bp.perm, 0)); } } } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index fb5c6fddedc6..0f22619fafa6 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -21,8 +21,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; import android.content.pm.PermissionInfo; +import android.content.pm.parsing.AndroidPackage; import android.permission.PermissionManagerInternal; import java.util.ArrayList; @@ -175,16 +175,14 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager public abstract void systemReady(); - public abstract boolean isPermissionsReviewRequired(@NonNull PackageParser.Package pkg, + public abstract boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg, @UserIdInt int userId); - public abstract void grantRuntimePermissionsGrantedToDisabledPackage( - @NonNull PackageParser.Package pkg, int callingUid); public abstract void grantRequestedRuntimePermissions( - @NonNull PackageParser.Package pkg, @NonNull int[] userIds, + @NonNull AndroidPackage pkg, @NonNull int[] userIds, @NonNull String[] grantedPermissions, int callingUid); public abstract void setWhitelistedRestrictedPermissions( - @NonNull PackageParser.Package pkg, @NonNull int[] userIds, + @NonNull AndroidPackage pkg, @NonNull int[] userIds, @NonNull List<String> permissions, int callingUid, @PackageManager.PermissionWhitelistFlags int whitelistFlags); /** Sets the whitelisted, restricted permissions for the given package. */ @@ -206,7 +204,7 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager * @param callback Callback to call after permission changes */ public abstract void updatePermissions(@NonNull String packageName, - @Nullable PackageParser.Package pkg); + @Nullable AndroidPackage pkg); /** * Update all permissions for all apps. @@ -226,7 +224,7 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager * Resets any user permission state changes (eg. permissions and flags) of all * packages installed for the given user. * - * @see #resetRuntimePermissions(android.content.pm.PackageParser.Package, int) + * @see #resetRuntimePermissions(AndroidPackage, int) */ public abstract void resetAllRuntimePermissions(@UserIdInt int userId); @@ -234,7 +232,7 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager * Resets any user permission state changes (eg. permissions and flags) of the * specified package for the given user. */ - public abstract void resetRuntimePermissions(@NonNull PackageParser.Package pkg, + public abstract void resetRuntimePermissions(@NonNull AndroidPackage pkg, @UserIdInt int userId); /** @@ -247,8 +245,8 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager * @param allPackageNames All packages */ public abstract void revokeRuntimePermissionsIfGroupChanged( - @NonNull PackageParser.Package newPackage, - @NonNull PackageParser.Package oldPackage, + @NonNull AndroidPackage newPackage, + @NonNull AndroidPackage oldPackage, @NonNull ArrayList<String> allPackageNames); /** @@ -257,9 +255,9 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager * NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to * the permission settings. */ - public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty); - public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty); - public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty); + public abstract void addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); + public abstract void addAllPermissionGroups(@NonNull AndroidPackage pkg, boolean chatty); + public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); /** Retrieve the packages that have requested the given app op permission */ public abstract @Nullable String[] getAppOpPermissionPackages( diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java index 3d8cf2ddc2cc..254b720c57a0 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java +++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java @@ -18,7 +18,7 @@ package com.android.server.pm.permission; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.pm.PackageParser; +import android.content.pm.parsing.ComponentParseUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -65,8 +65,8 @@ public class PermissionSettings { * name to permission group object. */ @GuardedBy("mLock") - final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups = - new ArrayMap<String, PackageParser.PermissionGroup>(); + final ArrayMap<String, ComponentParseUtils.ParsedPermissionGroup> mPermissionGroups = + new ArrayMap<>(); /** * Set of packages that request a particular app op. The mapping is from permission diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 9b9f93f7b5c4..b1feb148e5b3 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -37,8 +37,8 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal.PackageListObserver; -import android.content.pm.PackageParser; import android.content.pm.PermissionInfo; +import android.content.pm.parsing.AndroidPackage; import android.os.Build; import android.os.Process; import android.os.RemoteException; @@ -357,10 +357,10 @@ public final class PermissionPolicyService extends SystemService { pkg.sharedUserId, userId); if (sharedPkgNames != null) { for (String sharedPkgName : sharedPkgNames) { - final PackageParser.Package sharedPkg = packageManagerInternal + final AndroidPackage sharedPkg = packageManagerInternal .getPackage(sharedPkgName); if (sharedPkg != null) { - synchroniser.addPackage(sharedPkg.packageName); + synchroniser.addPackage(sharedPkg.getPackageName()); } } } @@ -377,7 +377,8 @@ public final class PermissionPolicyService extends SystemService { PackageManagerInternal.class); final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser( getUserContext(getContext(), UserHandle.of(userId))); - packageManagerInternal.forEachPackage((pkg) -> synchronizer.addPackage(pkg.packageName)); + packageManagerInternal.forEachPackage( + (pkg) -> synchronizer.addPackage(pkg.getPackageName())); synchronizer.syncPackages(); } @@ -676,10 +677,19 @@ public final class PermissionPolicyService extends SystemService { private void setUidMode(int opCode, int uid, int mode, @NonNull String packageName) { - final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager - .opToPublicName(opCode), uid, packageName); - if (currentMode != mode) { + final int oldMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( + opCode), uid, packageName); + if (oldMode != mode) { mAppOpsManager.setUidMode(opCode, uid, mode); + final int newMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( + opCode), uid, packageName); + if (newMode != mode) { + // Work around incorrectly-set package mode. It never makes sense for app ops + // related to runtime permissions, but can get in the way and we have to reset + // it. + mAppOpsManager.setMode(opCode, uid, packageName, AppOpsManager.opToDefaultMode( + opCode)); + } } } diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java index ff9129956a3b..a62bb74730f8 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java @@ -773,9 +773,9 @@ public class BatterySaverStateMachine { // Handle triggering the notification to show/hide when appropriate if (intReason == BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON) { - runOnBgThread(this::triggerDynamicModeNotification); + triggerDynamicModeNotification(); } else if (!enable) { - runOnBgThread(this::hideDynamicModeNotification); + hideDynamicModeNotification(); } if (DEBUG) { @@ -787,33 +787,42 @@ public class BatterySaverStateMachine { @VisibleForTesting void triggerDynamicModeNotification() { - NotificationManager manager = mContext.getSystemService(NotificationManager.class); - ensureNotificationChannelExists(manager, DYNAMIC_MODE_NOTIF_CHANNEL_ID, - R.string.dynamic_mode_notification_channel_name); - - manager.notifyAsUser(TAG, DYNAMIC_MODE_NOTIFICATION_ID, - buildNotification(DYNAMIC_MODE_NOTIF_CHANNEL_ID, - mContext.getResources().getString(R.string.dynamic_mode_notification_title), - R.string.dynamic_mode_notification_summary, - Intent.ACTION_POWER_USAGE_SUMMARY), - UserHandle.ALL); + // The current lock is the PowerManager lock, which sits very low in the service lock + // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock. + runOnBgThread(() -> { + NotificationManager manager = mContext.getSystemService(NotificationManager.class); + ensureNotificationChannelExists(manager, DYNAMIC_MODE_NOTIF_CHANNEL_ID, + R.string.dynamic_mode_notification_channel_name); + + manager.notifyAsUser(TAG, DYNAMIC_MODE_NOTIFICATION_ID, + buildNotification(DYNAMIC_MODE_NOTIF_CHANNEL_ID, + mContext.getResources().getString( + R.string.dynamic_mode_notification_title), + R.string.dynamic_mode_notification_summary, + Intent.ACTION_POWER_USAGE_SUMMARY), + UserHandle.ALL); + }); } @VisibleForTesting void triggerStickyDisabledNotification() { - NotificationManager manager = mContext.getSystemService(NotificationManager.class); - ensureNotificationChannelExists(manager, BATTERY_SAVER_NOTIF_CHANNEL_ID, - R.string.battery_saver_notification_channel_name); - - final String percentage = NumberFormat.getPercentInstance() - .format((double) mBatteryLevel / 100.0); - manager.notifyAsUser(TAG, STICKY_AUTO_DISABLED_NOTIFICATION_ID, - buildNotification(BATTERY_SAVER_NOTIF_CHANNEL_ID, - mContext.getResources().getString( - R.string.battery_saver_charged_notification_title, percentage), - R.string.battery_saver_off_notification_summary, - Settings.ACTION_BATTERY_SAVER_SETTINGS), - UserHandle.ALL); + // The current lock is the PowerManager lock, which sits very low in the service lock + // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock. + runOnBgThread(() -> { + NotificationManager manager = mContext.getSystemService(NotificationManager.class); + ensureNotificationChannelExists(manager, BATTERY_SAVER_NOTIF_CHANNEL_ID, + R.string.battery_saver_notification_channel_name); + + final String percentage = NumberFormat.getPercentInstance() + .format((double) mBatteryLevel / 100.0); + manager.notifyAsUser(TAG, STICKY_AUTO_DISABLED_NOTIFICATION_ID, + buildNotification(BATTERY_SAVER_NOTIF_CHANNEL_ID, + mContext.getResources().getString( + R.string.battery_saver_charged_notification_title, percentage), + R.string.battery_saver_off_notification_summary, + Settings.ACTION_BATTERY_SAVER_SETTINGS), + UserHandle.ALL); + }); } private void ensureNotificationChannelExists(NotificationManager manager, @@ -854,8 +863,12 @@ public class BatterySaverStateMachine { } private void hideNotification(int notificationId) { - NotificationManager manager = mContext.getSystemService(NotificationManager.class); - manager.cancel(notificationId); + // The current lock is the PowerManager lock, which sits very low in the service lock + // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock. + runOnBgThread(() -> { + NotificationManager manager = mContext.getSystemService(NotificationManager.class); + manager.cancelAsUser(TAG, notificationId, UserHandle.ALL); + }); } private void setStickyActive(boolean active) { diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index aac0f906feaa..a4eef9bf8d2e 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -308,12 +308,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C ByteArrayOutputStream out = new ByteArrayOutputStream(); pm.forEachInstalledPackage(FunctionalUtils.uncheckExceptions(pkg -> { - out.write(pkg.packageName.getBytes()); + out.write(pkg.getPackageName().getBytes()); out.write(BitUtils.toBytes(pkg.getLongVersionCode())); - out.write(pm.getApplicationEnabledState(pkg.packageName, userId)); + out.write(pm.getApplicationEnabledState(pkg.getPackageName(), userId)); ArraySet<String> enabledComponents = - pm.getEnabledComponents(pkg.packageName, userId); + pm.getEnabledComponents(pkg.getPackageName(), userId); int numComponents = CollectionUtils.size(enabledComponents); out.write(numComponents); for (int i = 0; i < numComponents; i++) { @@ -321,12 +321,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } ArraySet<String> disabledComponents = - pm.getDisabledComponents(pkg.packageName, userId); + pm.getDisabledComponents(pkg.getPackageName(), userId); numComponents = CollectionUtils.size(disabledComponents); for (int i = 0; i < numComponents; i++) { out.write(disabledComponents.valueAt(i).getBytes()); } - for (Signature signature : pkg.mSigningDetails.signatures) { + for (Signature signature : pkg.getSigningDetails().signatures) { out.write(signature.toByteArray()); } }), userId); diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index 83891f60d4f7..b84fd79c33fc 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -16,6 +16,13 @@ package com.android.server.rollback; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN; + +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; @@ -41,6 +48,7 @@ import android.util.StatsLog; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.server.PackageWatchdog; +import com.android.server.PackageWatchdog.FailureReasons; import com.android.server.PackageWatchdog.PackageHealthObserver; import com.android.server.PackageWatchdog.PackageHealthObserverImpact; @@ -95,8 +103,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve @Override public int onHealthCheckFailed(VersionedPackage failedPackage) { - if (getAvailableRollback(mContext.getSystemService(RollbackManager.class), failedPackage) - == null) { + if (getAvailableRollback(failedPackage) == null) { // Don't handle the notification, no rollbacks available for the package return PackageHealthObserverImpact.USER_IMPACT_NONE; } else { @@ -106,48 +113,15 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } @Override - public boolean execute(VersionedPackage failedPackage) { - RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); - VersionedPackage moduleMetadataPackage = getModuleMetadataPackage(); - RollbackInfo rollback = getAvailableRollback(rollbackManager, failedPackage); - + public boolean execute(VersionedPackage failedPackage, @FailureReasons int rollbackReason) { + RollbackInfo rollback = getAvailableRollback(failedPackage); if (rollback == null) { Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ " + failedPackage.getPackageName() + "] with versionCode: [" + failedPackage.getVersionCode() + "]"); return false; } - - logEvent(moduleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE); - LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> { - int status = result.getIntExtra(RollbackManager.EXTRA_STATUS, - RollbackManager.STATUS_FAILURE); - if (status == RollbackManager.STATUS_SUCCESS) { - if (rollback.isStaged()) { - int rollbackId = rollback.getRollbackId(); - synchronized (mPendingStagedRollbackIds) { - mPendingStagedRollbackIds.add(rollbackId); - } - BroadcastReceiver listener = - listenForStagedSessionReady(rollbackManager, rollbackId, - moduleMetadataPackage); - handleStagedSessionChange(rollbackManager, rollbackId, listener, - moduleMetadataPackage); - } else { - logEvent(moduleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS); - } - } else { - logEvent(moduleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); - } - }); - - mHandler.post(() -> - rollbackManager.commitRollback(rollback.getRollbackId(), - Collections.singletonList(failedPackage), - rollbackReceiver.getIntentSender())); + rollbackPackage(rollback, failedPackage, rollbackReason); // Assume rollback executed successfully return true; } @@ -176,9 +150,8 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller(); String moduleMetadataPackageName = getModuleMetadataPackageName(); - VersionedPackage newModuleMetadataPackage = getModuleMetadataPackage(); - if (getAvailableRollback(rollbackManager, newModuleMetadataPackage) != null) { + if (!rollbackManager.getAvailableRollbacks().isEmpty()) { scheduleCheckAndMitigateNativeCrashes(); } @@ -219,17 +192,19 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } if (sessionInfo.isStagedSessionApplied()) { logEvent(oldModuleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, + WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); } else if (sessionInfo.isStagedSessionReady()) { // TODO: What do for staged session ready but not applied } else { logEvent(oldModuleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); } } - private RollbackInfo getAvailableRollback(RollbackManager rollbackManager, - VersionedPackage failedPackage) { + private RollbackInfo getAvailableRollback(VersionedPackage failedPackage) { + RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) { for (PackageRollbackInfo packageRollback : rollback.getPackages()) { boolean hasFailedPackage = packageRollback.getPackageName().equals( @@ -271,7 +246,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager, - int rollbackId, VersionedPackage moduleMetadataPackage) { + int rollbackId, @Nullable VersionedPackage moduleMetadataPackage) { BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -286,7 +261,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId, - BroadcastReceiver listener, VersionedPackage moduleMetadataPackage) { + BroadcastReceiver listener, @Nullable VersionedPackage moduleMetadataPackage) { PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller(); List<RollbackInfo> recentRollbacks = @@ -303,12 +278,16 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve saveLastStagedRollbackId(rollbackId); logEvent(moduleMetadataPackage, StatsLog - .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED); + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED, + WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, + ""); mContext.getSystemService(PowerManager.class).reboot("Rollback staged install"); } else if (sessionInfo.isStagedSessionFailed() && markStagedSessionHandled(rollbackId)) { logEvent(moduleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, + ""); mContext.unregisterReceiver(listener); } } @@ -355,11 +334,12 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve return rollbackId; } - private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type) { + private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type, + int rollbackReason, @NonNull String failingPackageName) { Slog.i(TAG, "Watchdog event occurred of type: " + type); if (moduleMetadataPackage != null) { StatsLog.logWatchdogRollbackOccurred(type, moduleMetadataPackage.getPackageName(), - moduleMetadataPackage.getVersionCode()); + moduleMetadataPackage.getVersionCode(), rollbackReason, failingPackageName); } } @@ -371,7 +351,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve mNumberOfNativeCrashPollsRemaining--; // Check if native watchdog reported a crash if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) { - execute(getModuleMetadataPackage()); + rollbackAll(); // we stop polling after an attempt to execute rollback, regardless of whether the // attempt succeeds or not } else { @@ -383,6 +363,100 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } /** + * Returns true if the package name is the name of a module. + */ + private boolean isModule(String packageName) { + PackageManager pm = mContext.getPackageManager(); + try { + return pm.getModuleInfo(packageName, 0) != null; + } catch (PackageManager.NameNotFoundException ignore) { + return false; + } + } + + private VersionedPackage getVersionedPackage(String packageName) { + try { + return new VersionedPackage(packageName, mContext.getPackageManager().getPackageInfo( + packageName, 0 /* flags */).getLongVersionCode()); + } catch (PackageManager.NameNotFoundException e) { + return null; + } + } + + /** + * Rolls back the session that owns {@code failedPackage} + * + * @param rollback {@code rollbackInfo} of the {@code failedPackage} + * @param failedPackage the package that needs to be rolled back + */ + private void rollbackPackage(RollbackInfo rollback, VersionedPackage failedPackage, + @FailureReasons int rollbackReason) { + final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); + int reasonToLog = mapFailureReasonToMetric(rollbackReason); + final String failedPackageToLog; + if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) { + failedPackageToLog = SystemProperties.get( + "sys.init.updatable_crashing_process_name", ""); + } else { + failedPackageToLog = failedPackage.getPackageName(); + } + final VersionedPackage logPackage = isModule(failedPackage.getPackageName()) + ? getModuleMetadataPackage() + : null; + + logEvent(logPackage, + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE, + reasonToLog, failedPackageToLog); + final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> { + int status = result.getIntExtra(RollbackManager.EXTRA_STATUS, + RollbackManager.STATUS_FAILURE); + if (status == RollbackManager.STATUS_SUCCESS) { + if (rollback.isStaged()) { + int rollbackId = rollback.getRollbackId(); + synchronized (mPendingStagedRollbackIds) { + mPendingStagedRollbackIds.add(rollbackId); + } + BroadcastReceiver listener = + listenForStagedSessionReady(rollbackManager, rollbackId, + logPackage); + handleStagedSessionChange(rollbackManager, rollbackId, listener, + logPackage); + } else { + logEvent(logPackage, + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, + reasonToLog, failedPackageToLog); + } + } else { + logEvent(logPackage, + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + reasonToLog, failedPackageToLog); + } + }); + + mHandler.post(() -> + rollbackManager.commitRollback(rollback.getRollbackId(), + Collections.singletonList(failedPackage), + rollbackReceiver.getIntentSender())); + } + + private void rollbackAll() { + Slog.i(TAG, "Rolling back all available rollbacks"); + RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); + List<RollbackInfo> rollbacks = rollbackManager.getAvailableRollbacks(); + + for (RollbackInfo rollback : rollbacks) { + String samplePackageName = rollback.getPackages().get(0).getPackageName(); + VersionedPackage sampleVersionedPackage = getVersionedPackage(samplePackageName); + if (sampleVersionedPackage == null) { + Slog.e(TAG, "Failed to rollback " + samplePackageName); + continue; + } + rollbackPackage(rollback, sampleVersionedPackage, + PackageWatchdog.FAILURE_REASON_NATIVE_CRASH); + } + } + + /** * Since this method can eventually trigger a RollbackManager rollback, it should be called * only once boot has completed {@code onBootCompleted} and not earlier, because the install * session must be entirely completed before we try to rollback. @@ -392,4 +466,20 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve + "and mitigate native crashes"); mHandler.post(()->checkAndMitigateNativeCrashes()); } + + private int mapFailureReasonToMetric(@FailureReasons int failureReason) { + switch (failureReason) { + case PackageWatchdog.FAILURE_REASON_NATIVE_CRASH: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH; + case PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK; + case PackageWatchdog.FAILURE_REASON_APP_CRASH: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH; + case PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING; + default: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN; + } + } + } diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java index d76836f90e6b..46dd366f1909 100644 --- a/services/core/java/com/android/server/storage/StorageSessionController.java +++ b/services/core/java/com/android/server/storage/StorageSessionController.java @@ -43,7 +43,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import java.io.FileDescriptor; -import java.io.IOException; /** * Controls storage sessions for users initiated by the {@link StorageManagerService}. @@ -101,18 +100,10 @@ public final class StorageSessionController { connection = new StorageUserConnection(mContext, userId, this); mConnections.put(userId, connection); } - Slog.i(TAG, "Creating session with id: " + sessionId); - connection.createSession(sessionId, new ParcelFileDescriptor(deviceFd), + Slog.i(TAG, "Creating and starting session with id: " + sessionId); + connection.startSession(sessionId, new ParcelFileDescriptor(deviceFd), vol.getPath().getPath(), vol.getInternalPath().getPath()); } - - // At boot, a volume can be mounted before user is unlocked, in that case, we create it - // above and save it so that we can restart all sessions when the user is unlocked - if (mExternalStorageServiceComponent != null) { - connection.startSession(sessionId); - } else { - Slog.i(TAG, "Controller not initialised, session not started " + sessionId); - } } /** @@ -179,23 +170,32 @@ public final class StorageSessionController { * a session will be ignored. */ public void onUnlockUser(int userId) throws ExternalStorageServiceException { - if (!shouldHandle(null)) { - return; - } - Slog.i(TAG, "On user unlock " + userId); - if (userId == 0) { + if (shouldHandle(null) && userId == 0) { initExternalStorageServiceComponent(); } + } + /** + * Called when a user is in the process is being stopped. + * + * Does nothing if {@link #shouldHandle} is {@code false} + * + * This call removes all sessions for the user that is being stopped; + * this will make sure that we don't rebind to the service needlessly. + */ + public void onUserStopping(int userId) throws ExternalStorageServiceException { + if (!shouldHandle(null)) { + return; + } StorageUserConnection connection = null; synchronized (mLock) { connection = mConnections.get(userId); } if (connection != null) { - Slog.i(TAG, "Restarting all sessions for user: " + userId); - connection.startAllSessions(); + Slog.i(TAG, "Removing all sessions for user: " + userId); + connection.removeAllSessions(); } else { Slog.w(TAG, "No connection found for user: " + userId); } diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java index 7c4773033518..5c44eee4c789 100644 --- a/services/core/java/com/android/server/storage/StorageUserConnection.java +++ b/services/core/java/com/android/server/storage/StorageUserConnection.java @@ -34,6 +34,7 @@ import android.os.ParcelFileDescriptor; import android.os.ParcelableException; import android.os.RemoteCallback; import android.os.UserHandle; +import android.os.storage.StorageManagerInternal; import android.service.storage.ExternalStorageService; import android.service.storage.IExternalStorageService; import android.text.TextUtils; @@ -41,6 +42,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; +import com.android.server.LocalServices; import java.io.IOException; import java.util.HashMap; @@ -73,42 +75,25 @@ public final class StorageUserConnection { } /** - * Creates and stores a storage {@link Session}. + * Creates and starts a storage {@link Session}. * * They must also be cleaned up with {@link #removeSession}. * * @throws IllegalArgumentException if a {@code Session} with {@code sessionId} already exists */ - public void createSession(String sessionId, ParcelFileDescriptor pfd, String upperPath, - String lowerPath) { + public void startSession(String sessionId, ParcelFileDescriptor pfd, String upperPath, + String lowerPath) throws ExternalStorageServiceException { Preconditions.checkNotNull(sessionId); Preconditions.checkNotNull(pfd); Preconditions.checkNotNull(upperPath); Preconditions.checkNotNull(lowerPath); - synchronized (mLock) { - Preconditions.checkArgument(!mSessions.containsKey(sessionId)); - mSessions.put(sessionId, new Session(sessionId, pfd, upperPath, lowerPath)); - } - } - - /** - * Starts an already created storage {@link Session} for {@code sessionId}. - * - * It is safe to call this multiple times, however if the session is already started, - * subsequent calls will be ignored. - * - * @throws ExternalStorageServiceException if the session failed to start - **/ - public void startSession(String sessionId) throws ExternalStorageServiceException { - Session session; - synchronized (mLock) { - session = mSessions.get(sessionId); - } - prepareRemote(); synchronized (mLock) { - mActiveConnection.startSessionLocked(session); + Preconditions.checkArgument(!mSessions.containsKey(sessionId)); + Session session = new Session(sessionId, upperPath, lowerPath); + mSessions.put(sessionId, session); + mActiveConnection.startSessionLocked(session, pfd); } } @@ -121,16 +106,10 @@ public final class StorageUserConnection { **/ public Session removeSession(String sessionId) { synchronized (mLock) { - Session session = mSessions.remove(sessionId); - if (session != null) { - session.close(); - return session; - } - return null; + return mSessions.remove(sessionId); } } - /** * Removes a session and waits for exit * @@ -150,25 +129,29 @@ public final class StorageUserConnection { } } - /** Starts all available sessions for a user without blocking. Any failures will be ignored. */ - public void startAllSessions() { - try { - prepareRemote(); - } catch (ExternalStorageServiceException e) { - Slog.e(TAG, "Failed to start all sessions for user: " + mUserId, e); - return; + /** Restarts all available sessions for a user without blocking. + * + * Any failures will be ignored. + **/ + public void resetUserSessions() { + synchronized (mLock) { + if (mSessions.isEmpty()) { + // Nothing to reset if we have no sessions to restart; we typically + // hit this path if the user was consciously shut down. + return; + } } + StorageManagerInternal sm = LocalServices.getService(StorageManagerInternal.class); + sm.resetUser(mUserId); + } + /** + * Removes all sessions, without waiting. + */ + public void removeAllSessions() { synchronized (mLock) { - Slog.i(TAG, "Starting " + mSessions.size() + " sessions for user: " + mUserId + "..."); - for (Session session : mSessions.values()) { - try { - mActiveConnection.startSessionLocked(session); - } catch (IllegalStateException | ExternalStorageServiceException e) { - // TODO: Don't crash process? We could get into process crash loop - Slog.e(TAG, "Failed to start " + session, e); - } - } + Slog.i(TAG, "Removing " + mSessions.size() + " sessions for user: " + mUserId + "..."); + mSessions.clear(); } } @@ -269,26 +252,37 @@ public final class StorageUserConnection { return true; } - public void startSessionLocked(Session session) throws ExternalStorageServiceException { + public void startSessionLocked(Session session, ParcelFileDescriptor fd) + throws ExternalStorageServiceException { if (!isActiveLocked(session)) { + try { + fd.close(); + } catch (IOException e) { + // ignore + } return; } CountDownLatch latch = new CountDownLatch(1); - try (ParcelFileDescriptor dupedPfd = session.pfd.dup()) { + try { mRemote.startSession(session.sessionId, FLAG_SESSION_TYPE_FUSE | FLAG_SESSION_ATTRIBUTE_INDEXABLE, - dupedPfd, session.upperPath, session.lowerPath, new RemoteCallback(result -> + fd, session.upperPath, session.lowerPath, new RemoteCallback(result -> setResultLocked(latch, result))); waitForLatch(latch, "start_session " + session); maybeThrowExceptionLocked(); } catch (Exception e) { throw new ExternalStorageServiceException("Failed to start session: " + session, e); + } finally { + try { + fd.close(); + } catch (IOException e) { + // Ignore + } } } public void endSessionLocked(Session session) throws ExternalStorageServiceException { - session.close(); if (!isActiveLocked(session)) { // Nothing to end, not started yet return; @@ -390,7 +384,7 @@ public final class StorageUserConnection { // will be called for any required mounts. // Notify StorageManagerService so it can restart all necessary sessions close(); - new Thread(StorageUserConnection.this::startAllSessions).start(); + resetUserSessions(); } }; } @@ -411,29 +405,18 @@ public final class StorageUserConnection { } } - private static final class Session implements AutoCloseable { + private static final class Session { public final String sessionId; - public final ParcelFileDescriptor pfd; public final String lowerPath; public final String upperPath; - Session(String sessionId, ParcelFileDescriptor pfd, String upperPath, String lowerPath) { + Session(String sessionId, String upperPath, String lowerPath) { this.sessionId = sessionId; - this.pfd = pfd; this.upperPath = upperPath; this.lowerPath = lowerPath; } @Override - public void close() { - try { - pfd.close(); - } catch (IOException e) { - Slog.i(TAG, "Failed to close session: " + this); - } - } - - @Override public String toString() { return "[SessionId: " + sessionId + ". UpperPath: " + upperPath + ". LowerPath: " + lowerPath + "]"; diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java index 340fe3dbaa97..4e8ba078a73c 100644 --- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java +++ b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java @@ -66,7 +66,8 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy { private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000; // A log for changes made to the system clock and why. - @NonNull private final LocalLog mTimeChangesLog = new LocalLog(30); + @NonNull + private final LocalLog mTimeChangesLog = new LocalLog(30, false /* useLocalTimestamps */); // @NonNull after initialize() private Callback mCallback; diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java index e034ad437555..adf6d7e51f4f 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java @@ -20,13 +20,9 @@ import android.annotation.Nullable; import android.app.AlarmManager; import android.content.ContentResolver; import android.content.Context; -import android.content.Intent; import android.os.SystemProperties; -import android.os.UserHandle; import android.provider.Settings; -import com.android.internal.telephony.TelephonyIntents; - /** * The real implementation of {@link TimeZoneDetectorStrategy.Callback}. */ @@ -66,16 +62,8 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat } @Override - public void setDeviceTimeZone(String zoneId, boolean sendNetworkBroadcast) { + public void setDeviceTimeZone(String zoneId) { AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class); alarmManager.setTimeZone(zoneId); - - if (sendNetworkBroadcast) { - // TODO Nothing in the platform appears to listen for this. Remove it. - Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - intent.putExtra("time-zone", zoneId); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } } } diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java index 5db12c7ac872..b4d80531be54 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java @@ -86,7 +86,7 @@ public class TimeZoneDetectorStrategy { /** * Sets the device's time zone. */ - void setDeviceTimeZone(@NonNull String zoneId, boolean sendNetworkBroadcast); + void setDeviceTimeZone(@NonNull String zoneId); } private static final String LOG_TAG = "TimeZoneDetectorStrategy"; @@ -172,7 +172,7 @@ public class TimeZoneDetectorStrategy { * (for use during debugging). */ @NonNull - private final LocalLog mTimeZoneChangesLog = new LocalLog(30); + private final LocalLog mTimeZoneChangesLog = new LocalLog(30, false /* useLocalTimestamps */); /** * A mapping from phoneId to a linked list of phone time zone suggestions (the head being the @@ -333,7 +333,6 @@ public class TimeZoneDetectorStrategy { Objects.requireNonNull(newZoneId); Objects.requireNonNull(cause); - boolean sendNetworkBroadcast = (origin == ORIGIN_PHONE); boolean isOriginAutomatic = isOriginAutomatic(origin); if (isOriginAutomatic) { if (!mCallback.isAutoTimeZoneDetectionEnabled()) { @@ -373,12 +372,11 @@ public class TimeZoneDetectorStrategy { return; } - mCallback.setDeviceTimeZone(newZoneId, sendNetworkBroadcast); + mCallback.setDeviceTimeZone(newZoneId); String msg = "Set device time zone." + " origin=" + origin + ", currentZoneId=" + currentZoneId + ", newZoneId=" + newZoneId - + ", sendNetworkBroadcast" + sendNetworkBroadcast + ", cause=" + cause; if (DBG) { Slog.d(LOG_TAG, msg); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5d796055dcc7..25079ec758b3 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -620,10 +620,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // TODO: Make this final int mTargetSdk; - // Set to true when this app creates a surface while in the middle of an animation. In that - // case do not clear allDrawn until the animation completes. - boolean deferClearAllDrawn; - // Is this window's surface needed? This is almost like visible, except // it will sometimes be true a little earlier: when the activity record has // been shown, but is still waiting for its app transition to execute @@ -771,10 +767,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.print(" primaryColor="); pw.println(Integer.toHexString(taskDescription.getPrimaryColor())); pw.print(prefix + " backgroundColor="); - pw.println(Integer.toHexString(taskDescription.getBackgroundColor())); - pw.print(prefix + " statusBarColor="); - pw.println(Integer.toHexString(taskDescription.getStatusBarColor())); - pw.print(prefix + " navigationBarColor="); + pw.print(Integer.toHexString(taskDescription.getBackgroundColor())); + pw.print(" statusBarColor="); + pw.print(Integer.toHexString(taskDescription.getStatusBarColor())); + pw.print(" navigationBarColor="); pw.println(Integer.toHexString(taskDescription.getNavigationBarColor())); } } @@ -847,14 +843,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.println(requestedVrComponent); } super.dump(pw, prefix, dumpAll); - pw.print(" visible="); pw.print(mVisible); - if (appToken != null) { - pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction); + if (mVoiceInteraction) { + pw.println(prefix + "mVoiceInteraction=true"); } - pw.print(prefix); pw.print(" mOccludesParent="); pw.print(mOccludesParent); + pw.print(prefix); pw.print("mOccludesParent="); pw.print(mOccludesParent); pw.print(" mOrientation="); pw.println(mOrientation); pw.println(prefix + "mVisibleRequested=" + mVisibleRequested - + " mClientVisible=" + mClientVisible + + " mVisible=" + mVisible + " mClientVisible=" + mClientVisible + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "") + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible); if (paused) { @@ -901,7 +896,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay); } if (lastVisibleTime != 0 || nowVisible) { - pw.print(prefix); pw.print(" nowVisible="); pw.print(nowVisible); + pw.print(prefix); pw.print("nowVisible="); pw.print(nowVisible); pw.print(" lastVisibleTime="); if (lastVisibleTime == 0) pw.print("0"); else TimeUtils.formatDuration(lastVisibleTime, now, pw); @@ -3235,7 +3230,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // to move that animation to the new one. if (fromActivity.allDrawn) { allDrawn = true; - deferClearAllDrawn = fromActivity.deferClearAllDrawn; } if (fromActivity.firstWindowDrawn) { firstWindowDrawn = true; @@ -3719,7 +3713,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void clearAllDrawn() { allDrawn = false; - deferClearAllDrawn = false; } /** @@ -6145,10 +6138,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (mCompatDisplayInsets == null || !shouldUseSizeCompatMode()) { return false; } - final Configuration resolvedConfig = getResolvedOverrideConfiguration(); - final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds(); - if (resolvedAppBounds == null) { - // The override configuration has not been resolved yet. + final Rect appBounds = getConfiguration().windowConfiguration.getAppBounds(); + if (appBounds == null) { + // The app bounds hasn't been computed yet. return false; } @@ -6156,13 +6148,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Although colorMode, screenLayout, smallestScreenWidthDp are also fixed, generally these // fields should be changed with density and bounds, so here only compares the most // significant field. - if (parentConfig.densityDpi != resolvedConfig.densityDpi) { + if (parentConfig.densityDpi != getConfiguration().densityDpi) { return true; } final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds(); - final int appWidth = resolvedAppBounds.width(); - final int appHeight = resolvedAppBounds.height(); + final int appWidth = appBounds.width(); + final int appHeight = appBounds.height(); final int parentAppWidth = parentAppBounds.width(); final int parentAppHeight = parentAppBounds.height(); if (parentAppWidth == appWidth && parentAppHeight == appHeight) { @@ -6181,7 +6173,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // The rest of the condition is that only one side is smaller than the parent, but it still // needs to exclude the cases where the size is limited by the fixed aspect ratio. if (info.maxAspectRatio > 0) { - final float aspectRatio = Math.max(appWidth, appHeight) / Math.min(appWidth, appHeight); + final float aspectRatio = + (float) Math.max(appWidth, appHeight) / Math.min(appWidth, appHeight); if (aspectRatio >= info.maxAspectRatio) { // The current size has reached the max aspect ratio. return false; @@ -6533,7 +6526,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } else if (mCompatDisplayInsets != null) { // The override changes can only be obtained from display, because we don't have the // difference of full configuration in each hierarchy. - final int displayChanges = display.getLastOverrideConfigurationChanges(); + final int displayChanges = display.getCurrentOverrideConfigurationChanges(); final int orientationChanges = CONFIG_WINDOW_CONFIGURATION | CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION; final boolean hasNonOrienSizeChanged = hasResizeChange(displayChanges) diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index e9ad0d361b07..d7f4b34ba56d 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -389,7 +389,6 @@ public class AppTransitionController { // this guy's animations regardless of whether it's // gotten drawn. wtoken.allDrawn = true; - wtoken.deferClearAllDrawn = false; // Ensure that apps that are mid-starting are also scheduled to have their // starting windows removed after the animation is complete if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) { diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index bfa72e0eff78..bd0ea3d06853 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -81,9 +81,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { */ private Configuration mFullConfiguration = new Configuration(); - /** The bit mask of the last override fields of full configuration. */ - private int mLastOverrideConfigurationChanges; - /** * Contains merged override configuration settings from the top of the hierarchy down to this * particular instance. It is different from {@link #mFullConfiguration} because it starts from @@ -121,11 +118,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { return mFullConfiguration; } - /** Returns the last changes from applying override configuration. */ - int getLastOverrideConfigurationChanges() { - return mLastOverrideConfigurationChanges; - } - /** * Notify that parent config changed and we need to update full configuration. * @see #mFullConfiguration @@ -141,8 +133,7 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration); resolveOverrideConfiguration(newParentConfig); mFullConfiguration.setTo(newParentConfig); - mLastOverrideConfigurationChanges = - mFullConfiguration.updateFrom(mResolvedOverrideConfiguration); + mFullConfiguration.updateFrom(mResolvedOverrideConfiguration); if (!mResolvedTmpConfig.equals(mResolvedOverrideConfiguration)) { onMergedOverrideConfigurationChanged(); // This depends on the assumption that change-listeners don't do diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 8e126b56a736..374b72202e29 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -346,6 +346,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo /** The desired scaling factor for compatible apps. */ float mCompatibleScreenScale; + /** @see #getCurrentOverrideConfigurationChanges */ + private int mCurrentOverrideConfigurationChanges; + /** * Orientation forced by some window. If there is no visible window that specifies orientation * it is set to {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}. @@ -1867,6 +1870,25 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mTaskStackContainers.onStackWindowingModeChanged(stack); } + /** + * The value is only valid in the scope {@link #onRequestedOverrideConfigurationChanged} of the + * changing hierarchy and the {@link #onConfigurationChanged} of its children. + * + * @return The current changes ({@link android.content.pm.ActivityInfo.Config}) of requested + * override configuration. + */ + int getCurrentOverrideConfigurationChanges() { + return mCurrentOverrideConfigurationChanges; + } + + @Override + public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) { + mCurrentOverrideConfigurationChanges = + getRequestedOverrideConfiguration().diff(overrideConfiguration); + super.onRequestedOverrideConfigurationChanged(overrideConfiguration); + mCurrentOverrideConfigurationChanges = 0; + } + @Override public void onConfigurationChanged(Configuration newParentConfig) { final int lastOrientation = getConfiguration().orientation; diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java index df7c07055e87..470a02e5bd44 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java +++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java @@ -642,7 +642,8 @@ class DisplayWindowSettings { if (mIdentifier == IDENTIFIER_PORT && displayInfo.address != null) { // Config suggests using port as identifier for physical displays. if (displayInfo.address instanceof DisplayAddress.Physical) { - return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort(); + byte port = ((DisplayAddress.Physical) displayInfo.address).getPort(); + return "port:" + Byte.toUnsignedInt(port); } } return displayInfo.uniqueId; diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index c42029155bd0..175fccbdd0ba 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -439,10 +439,6 @@ class WindowStateAnimator { if (!mWin.mActivityRecord.isAnimating(TRANSITION)) { mWin.mActivityRecord.clearAllDrawn(); - } else { - // Currently animating, persist current state of allDrawn until animation - // is complete. - mWin.mActivityRecord.deferClearAllDrawn = true; } } diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index f81713ed4385..53edf9d3086a 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -280,10 +280,11 @@ class WindowToken extends WindowContainer<WindowState> { super.dump(pw, prefix, dumpAll); pw.print(prefix); pw.print("windows="); pw.println(mChildren); pw.print(prefix); pw.print("windowType="); pw.print(windowType); - pw.print(" hasVisible="); pw.println(hasVisible); + pw.print(" hasVisible="); pw.print(hasVisible); if (waitingToShow) { - pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow); + pw.print(" waitingToShow=true"); } + pw.println(); } @Override diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index cb599be82aa6..ee0449d95e00 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -4345,6 +4345,40 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + /** + * Get the list of active admins for an affected user: + * <ul> + * <li>The active admins associated with the userHandle itself</li> + * <li>The parent active admins for each managed profile associated with the userHandle</li> + * </ul> + * + * @param userHandle the affected user for whom to get the active admins + * @param parent whether the parent active admins should be included in the list of active + * admins or not + * @return the list of active admins for the affected user + */ + private List<ActiveAdmin> getActiveAdminsForAffectedUser(int userHandle, boolean parent) { + if (!parent) { + return getUserDataUnchecked(userHandle).mAdminList; + } + ArrayList<ActiveAdmin> admins = new ArrayList<>(); + for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) { + DevicePolicyData policy = getUserData(userInfo.id); + if (!userInfo.isManagedProfile()) { + admins.addAll(policy.mAdminList); + } else { + // For managed profiles, policies set on the parent profile will be included + for (int i = 0; i < policy.mAdminList.size(); i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (admin.hasParentActiveAdmin()) { + admins.add(admin.getParentActiveAdmin()); + } + } + } + } + return admins; + } + private boolean isSeparateProfileChallengeEnabled(int userHandle) { long ident = mInjector.binderClearCallingIdentity(); try { @@ -5096,118 +5130,58 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private boolean canPOorDOCallResetPassword(ActiveAdmin admin, @UserIdInt int userId) { - // Only if the admins targets a pre-O SDK - return getTargetSdk(admin.info.getPackageName(), userId) < Build.VERSION_CODES.O; - } - - /* PO or DO could do an untrusted reset in certain conditions. */ - private boolean canUserHaveUntrustedCredentialReset(@UserIdInt int userId) { - synchronized (getLockObject()) { - // An active DO or PO might be able to fo an untrusted credential reset - for (final ActiveAdmin admin : getUserData(userId).mAdminList) { - if (!isActiveAdminWithPolicyForUserLocked(admin, - DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, userId)) { - continue; - } - if (canPOorDOCallResetPassword(admin, userId)) { - return true; - } - } - return false; + private boolean setPasswordPrivileged(@NonNull String password, int flags, int callingUid) { + // Only allow setting password on an unsecured user + if (isLockScreenSecureUnchecked(UserHandle.getUserId(callingUid))) { + throw new SecurityException("Cannot change current password"); } + return resetPasswordInternal(password, 0, null, flags, callingUid); } + @Override - public boolean resetPassword(String passwordOrNull, int flags) throws RemoteException { + public boolean resetPassword(@Nullable String password, int flags) throws RemoteException { if (!mLockPatternUtils.hasSecureLockScreen()) { Slog.w(LOG_TAG, "Cannot reset password when the device has no lock screen"); return false; } - + if (password == null) password = ""; final int callingUid = mInjector.binderGetCallingUid(); final int userHandle = mInjector.userHandleGetCallingUserId(); - String password = passwordOrNull != null ? passwordOrNull : ""; - - // Password resetting to empty/null is not allowed for managed profiles. - if (TextUtils.isEmpty(password)) { - enforceNotManagedProfile(userHandle, "clear the active password"); + // As of R, only privlleged caller holding RESET_PASSWORD can call resetPassword() to + // set password to an unsecured user. + if (mContext.checkCallingPermission(permission.RESET_PASSWORD) + == PackageManager.PERMISSION_GRANTED) { + return setPasswordPrivileged(password, flags, callingUid); } synchronized (getLockObject()) { - // If caller has PO (or DO) it can change the password, so see if that's the case first. + // If caller has PO (or DO) throw or fail silently depending on its target SDK level. ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked( null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, callingUid); - final boolean preN; if (admin != null) { - if (!canPOorDOCallResetPassword(admin, userHandle)) { - throw new SecurityException("resetPassword() is deprecated for DPC targeting O" - + " or later"); - } - preN = getTargetSdk(admin.info.getPackageName(), - userHandle) <= android.os.Build.VERSION_CODES.M; - } else { - // Otherwise, make sure the caller has any active admin with the right policy or - // the required permission. - admin = getActiveAdminOrCheckPermissionForCallerLocked( - null, - DeviceAdminInfo.USES_POLICY_RESET_PASSWORD, - android.Manifest.permission.RESET_PASSWORD); - // Cannot be preN if admin is null because an exception would have been - // thrown before getting here - preN = admin == null ? false : getTargetSdk(admin.info.getPackageName(), - userHandle) <= android.os.Build.VERSION_CODES.M; - - // As of N, password resetting to empty/null is not allowed anymore. - // TODO Should we allow DO/PO to set an empty password? - if (TextUtils.isEmpty(password)) { - if (!preN) { - throw new SecurityException("Cannot call with null password"); - } else { - Slog.e(LOG_TAG, "Cannot call with null password"); - return false; - } - } - // As of N, password cannot be changed by the admin if it is already set. - if (isLockScreenSecureUnchecked(userHandle)) { - if (!preN) { - throw new SecurityException("Cannot change current password"); - } else { - Slog.e(LOG_TAG, "Cannot change current password"); - return false; - } - } - } - // Do not allow to reset password when current user has a managed profile - if (!isManagedProfile(userHandle)) { - for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) { - if (userInfo.isManagedProfile()) { - if (!preN) { - throw new IllegalStateException( - "Cannot reset password on user has managed profile"); - } else { - Slog.e(LOG_TAG, "Cannot reset password on user has managed profile"); - return false; - } - } - } - } - // Do not allow to reset password when user is locked - if (!mUserManager.isUserUnlocked(userHandle)) { - if (!preN) { - throw new IllegalStateException("Cannot reset password when user is locked"); - } else { - Slog.e(LOG_TAG, "Cannot reset password when user is locked"); + if (getTargetSdk(admin.info.getPackageName(), userHandle) < Build.VERSION_CODES.O) { + Slog.e(LOG_TAG, "DPC can no longer call resetPassword()"); return false; } + throw new SecurityException("Device admin can no longer call resetPassword()"); } - } - return resetPasswordInternal(password, 0, null, flags, callingUid, userHandle); + // Legacy device admin cannot call resetPassword either + admin = getActiveAdminForCallerLocked( + null, DeviceAdminInfo.USES_POLICY_RESET_PASSWORD, false); + if (getTargetSdk(admin.info.getPackageName(), + userHandle) <= android.os.Build.VERSION_CODES.M) { + Slog.e(LOG_TAG, "Device admin can no longer call resetPassword()"); + return false; + } + throw new SecurityException("Device admin can no longer call resetPassword()"); + } } private boolean resetPasswordInternal(String password, long tokenHandle, byte[] token, - int flags, int callingUid, int userHandle) { + int flags, int callingUid) { + final int userHandle = UserHandle.getUserId(callingUid); synchronized (getLockObject()) { final PasswordMetrics minMetrics = getPasswordMinimumMetrics(userHandle); final List<PasswordValidationError> validationErrors; @@ -5245,21 +5219,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // Don't do this with the lock held, because it is going to call // back in to the service. final long ident = mInjector.binderClearCallingIdentity(); - final boolean result; final LockscreenCredential newCredential = LockscreenCredential.createPasswordOrNone(password); try { - if (token == null) { - // This is the legacy reset password for DPM. Here we want to be able to override - // the old device password without necessarily knowing it. - mLockPatternUtils.setLockCredential( - newCredential, - LockscreenCredential.createNone(), - userHandle, /*allowUntrustedChange */true); - result = true; + if (tokenHandle == 0 || token == null) { + if (!mLockPatternUtils.setLockCredential(newCredential, + LockscreenCredential.createNone(), userHandle)) { + return false; + } } else { - result = mLockPatternUtils.setLockCredentialWithToken(newCredential, tokenHandle, - token, userHandle); + if (!mLockPatternUtils.setLockCredentialWithToken(newCredential, tokenHandle, + token, userHandle)) { + return false; + } } boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0; if (requireEntry) { @@ -5276,7 +5248,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } finally { mInjector.binderRestoreCallingIdentity(ident); } - return result; + return true; } private boolean isLockScreenSecureUnchecked(int userId) { @@ -7769,22 +7741,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * Disables all device cameras according to the specified admin. */ @Override - public void setCameraDisabled(ComponentName who, boolean disabled) { + public void setCameraDisabled(ComponentName who, boolean disabled, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = mInjector.userHandleGetCallingUserId(); + int userHandle = mInjector.userHandleGetCallingUserId(); synchronized (getLockObject()) { ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA); + DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent); + if (parent) { + enforceProfileOwnerOfOrganizationOwnedDevice(ap); + } if (ap.disableCamera != disabled) { ap.disableCamera = disabled; saveSettingsLocked(userHandle); } } // Tell the user manager that the restrictions have changed. - pushUserRestrictions(userHandle); + pushUserRestrictions(parent ? getProfileParentId(userHandle) : userHandle); DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_CAMERA_DISABLED) .setAdmin(who) @@ -7797,18 +7772,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * active admins. */ @Override - public boolean getCameraDisabled(ComponentName who, int userHandle) { - return getCameraDisabled(who, userHandle, /* mergeDeviceOwnerRestriction= */ true); + public boolean getCameraDisabled(ComponentName who, int userHandle, boolean parent) { + return getCameraDisabled(who, userHandle, /* mergeDeviceOwnerRestriction= */ true, parent); } private boolean getCameraDisabled(ComponentName who, int userHandle, - boolean mergeDeviceOwnerRestriction) { + boolean mergeDeviceOwnerRestriction, boolean parent) { if (!mHasFeature) { return false; } + if (parent) { + ActiveAdmin ap = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent); + enforceProfileOwnerOfOrganizationOwnedDevice(ap); + } synchronized (getLockObject()) { if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return (admin != null) ? admin.disableCamera : false; } // First, see if DO has set it. If so, it's device-wide. @@ -7818,13 +7798,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return true; } } - - // Then check each device admin on the user. - DevicePolicyData policy = getUserData(userHandle); + // Return the strictest policy across all participating admins. + List<ActiveAdmin> admins = getActiveAdminsForAffectedUser(userHandle, parent); // Determine whether or not the device camera is disabled for any active admins. - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); + for (ActiveAdmin admin: admins) { if (admin.disableCamera) { return true; } @@ -8636,6 +8613,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return null; } + @GuardedBy("getLockObject()") + ActiveAdmin getProfileOwnerOfOrganizationOwnedDeviceLocked(int userHandle) { + final long ident = mInjector.binderClearCallingIdentity(); + try { + for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) { + if (userInfo.isManagedProfile()) { + if (getProfileOwner(userInfo.id) != null + && canProfileOwnerAccessDeviceIds(userInfo.id)) { + ComponentName who = getProfileOwner(userInfo.id); + return getActiveAdminUncheckedLocked(who, userInfo.id); + } + } + } + } finally { + mInjector.binderRestoreCallingIdentity(ident); + } + return null; + } + @Override public String getProfileOwnerName(int userHandle) { if (!mHasFeature) { @@ -10323,7 +10319,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private void pushUserRestrictions(int userId) { synchronized (getLockObject()) { final boolean isDeviceOwner = mOwners.isDeviceOwnerUserId(userId); - final Bundle userRestrictions; + Bundle userRestrictions = null; final int restrictionOwnerType; if (isDeviceOwner) { @@ -10335,42 +10331,60 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { addOrRemoveDisableCameraRestriction(userRestrictions, deviceOwner); restrictionOwnerType = UserManagerInternal.OWNER_TYPE_DEVICE_OWNER; } else { - final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId); - userRestrictions = profileOwner != null ? profileOwner.userRestrictions : null; - addOrRemoveDisableCameraRestriction(userRestrictions, userId); + final ActiveAdmin profileOwnerOfOrganizationOwnedDevice = + getProfileOwnerOfOrganizationOwnedDeviceLocked(userId); - if (isProfileOwnerOfOrganizationOwnedDevice(profileOwner)) { + // If profile owner of an organization owned device, the restrictions will be + // pushed to the parent instance. + if (profileOwnerOfOrganizationOwnedDevice != null && !isManagedProfile(userId)) { restrictionOwnerType = UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE; - } else if (profileOwner != null) { - restrictionOwnerType = UserManagerInternal.OWNER_TYPE_PROFILE_OWNER; + final ActiveAdmin parent = profileOwnerOfOrganizationOwnedDevice + .getParentActiveAdmin(); + userRestrictions = parent.userRestrictions; + userRestrictions = addOrRemoveDisableCameraRestriction(userRestrictions, + parent); } else { - restrictionOwnerType = UserManagerInternal.OWNER_TYPE_NO_OWNER; + final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId); + + if (profileOwner != null) { + userRestrictions = profileOwner.userRestrictions; + restrictionOwnerType = UserManagerInternal.OWNER_TYPE_PROFILE_OWNER; + } else { + restrictionOwnerType = UserManagerInternal.OWNER_TYPE_NO_OWNER; + } + userRestrictions = addOrRemoveDisableCameraRestriction( + userRestrictions, userId); } } - mUserManagerInternal.setDevicePolicyUserRestrictions(userId, userRestrictions, restrictionOwnerType); } } - private void addOrRemoveDisableCameraRestriction(Bundle userRestrictions, ActiveAdmin admin) { - if (userRestrictions == null) return; + private Bundle addOrRemoveDisableCameraRestriction(Bundle userRestrictions, ActiveAdmin admin) { + if (userRestrictions == null) { + userRestrictions = new Bundle(); + } if (admin.disableCamera) { userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true); } else { userRestrictions.remove(UserManager.DISALLOW_CAMERA); } + return userRestrictions; } - private void addOrRemoveDisableCameraRestriction(Bundle userRestrictions, int userId) { - if (userRestrictions == null) return; + private Bundle addOrRemoveDisableCameraRestriction(Bundle userRestrictions, int userId) { + if (userRestrictions == null) { + userRestrictions = new Bundle(); + } if (getCameraDisabled(/* who= */ null, userId, /* mergeDeviceOwnerRestriction= */ false)) { userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true); } else { userRestrictions.remove(UserManager.DISALLOW_CAMERA); } + return userRestrictions; } @Override @@ -11673,11 +11687,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public boolean canUserHaveUntrustedCredentialReset(@UserIdInt int userId) { - return DevicePolicyManagerService.this.canUserHaveUntrustedCredentialReset(userId); - } - - @Override public CharSequence getPrintingDisabledReasonForUser(@UserIdInt int userId) { synchronized (getLockObject()) { if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_PRINTING, @@ -13890,7 +13899,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (policy.mPasswordTokenHandle != 0) { final String password = passwordOrNull != null ? passwordOrNull : ""; return resetPasswordInternal(password, policy.mPasswordTokenHandle, token, - flags, mInjector.binderGetCallingUid(), userHandle); + flags, mInjector.binderGetCallingUid()); } else { Slog.w(LOG_TAG, "No saved token handle"); } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 66f01f367493..b6e501a785ef 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -47,6 +47,7 @@ import android.net.TetheringManager; import android.os.BaseBundle; import android.os.Binder; import android.os.Build; +import android.os.Debug; import android.os.Environment; import android.os.FactoryTest; import android.os.FileUtils; @@ -108,6 +109,7 @@ import com.android.server.input.InputManagerService; import com.android.server.inputmethod.InputMethodManagerService; import com.android.server.inputmethod.InputMethodSystemProperty; import com.android.server.inputmethod.MultiClientInputMethodManagerService; +import com.android.server.integrity.AppIntegrityManagerService; import com.android.server.lights.LightsService; import com.android.server.media.MediaResourceMonitorService; import com.android.server.media.MediaRouterService; @@ -447,10 +449,6 @@ public final class SystemServer { // Mmmmmm... more memory! VMRuntime.getRuntime().clearGrowthLimit(); - // The system server has to run all of the time, so it needs to be - // as efficient as possible with its memory usage. - VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); - // Some devices rely on runtime fingerprint generation, so make sure // we've defined it before booting further. Build.ensureFingerprintProperty(); @@ -502,6 +500,24 @@ public final class SystemServer { LocalServices.addService(SystemServiceManager.class, mSystemServiceManager); // Prepare the thread pool for init tasks that can be parallelized SystemServerInitThreadPool.start(); + // Attach JVMTI agent if this is a debuggable build and the system property is set. + if (Build.IS_DEBUGGABLE) { + // Property is of the form "library_path=parameters". + String jvmtiAgent = SystemProperties.get("persist.sys.dalvik.jvmtiagent"); + if (!jvmtiAgent.isEmpty()) { + int equalIndex = jvmtiAgent.indexOf('='); + String libraryPath = jvmtiAgent.substring(0, equalIndex); + String parameterList = + jvmtiAgent.substring(equalIndex + 1, jvmtiAgent.length()); + // Attach the agent. + try { + Debug.attachJvmtiAgent(libraryPath, parameterList, null); + } catch (Exception e) { + Slog.e("System", "*************************************************"); + Slog.e("System", "********** Failed to load jvmti plugin: " + jvmtiAgent); + } + } + } } finally { t.traceEnd(); // InitBeforeStartServices } @@ -1114,6 +1130,10 @@ public final class SystemServer { SignedConfigService.registerUpdateReceiver(mSystemContext); t.traceEnd(); + t.traceBegin("AppIntegrityService"); + mSystemServiceManager.startService(AppIntegrityManagerService.class); + t.traceEnd(); + } catch (Throwable e) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting core service"); diff --git a/services/net/java/android/net/NetworkMonitorManager.java b/services/net/java/android/net/NetworkMonitorManager.java index 0f41302c0b15..0f669817f52e 100644 --- a/services/net/java/android/net/NetworkMonitorManager.java +++ b/services/net/java/android/net/NetworkMonitorManager.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.Hide; import android.annotation.NonNull; import android.os.Binder; import android.os.RemoteException; @@ -33,6 +34,7 @@ import android.util.Log; * wrapper methods in this class return a boolean that callers can use to determine whether * RemoteException was thrown. */ +@Hide public class NetworkMonitorManager { @NonNull private final INetworkMonitor mNetworkMonitor; diff --git a/services/net/java/android/net/ip/IpClientManager.java b/services/net/java/android/net/ip/IpClientManager.java index 4b7ed3c7b72f..09e333ee3471 100644 --- a/services/net/java/android/net/ip/IpClientManager.java +++ b/services/net/java/android/net/ip/IpClientManager.java @@ -16,6 +16,7 @@ package android.net.ip; +import android.annotation.Hide; import android.annotation.NonNull; import android.net.NattKeepalivePacketData; import android.net.ProxyInfo; @@ -38,6 +39,7 @@ import android.util.Log; * wrapper methods in this class return a boolean that callers can use to determine whether * RemoteException was thrown. */ +@Hide public class IpClientManager { @NonNull private final IIpClient mIpClient; @NonNull private final String mTag; diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java index 9e255fe19881..3518dc599cef 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -53,9 +53,12 @@ import java.util.LinkedList; @SmallTest @RunWith(AndroidJUnit4.class) public class LocalDisplayAdapterTest { - private static final long HANDLER_WAIT_MS = 100; + private static final Long DISPLAY_MODEL = Long.valueOf(0xAAAAAAAAL); + private static final int PORT_A = 0; + private static final int PORT_B = 0x80; + private static final int PORT_C = 0xFF; - private static final int PHYSICAL_DISPLAY_ID_MODEL_SHIFT = 8; + private static final long HANDLER_WAIT_MS = 100; private StaticMockitoSession mMockitoSession; @@ -74,7 +77,7 @@ public class LocalDisplayAdapterTest { private TestListener mListener = new TestListener(); - private LinkedList<Long> mDisplayIds = new LinkedList<>(); + private LinkedList<DisplayAddress.Physical> mAddresses = new LinkedList<>(); @Before public void setUp() throws Exception { @@ -106,30 +109,22 @@ public class LocalDisplayAdapterTest { */ @Test public void testPrivateDisplay() throws Exception { - // needs default one always - final long displayId0 = 0; - setUpDisplay(new DisplayConfig(displayId0, createDummyDisplayInfo())); - final long displayId1 = 1; - setUpDisplay(new DisplayConfig(displayId1, createDummyDisplayInfo())); - final long displayId2 = 2; - setUpDisplay(new DisplayConfig(displayId2, createDummyDisplayInfo())); + setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_A), createDummyDisplayInfo())); + setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_B), createDummyDisplayInfo())); + setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_C), createDummyDisplayInfo())); updateAvailableDisplays(); - // display 1 should be marked as private while display 2 is not. - doReturn(new int[]{(int) displayId1}).when(mMockedResources) + doReturn(new int[]{ PORT_B }).when(mMockedResources) .getIntArray(com.android.internal.R.array.config_localPrivateDisplayPorts); mAdapter.registerLocked(); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); // This should be public - assertDisplay(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), displayId0, - false); + assertDisplay(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), PORT_A, false); // This should be private - assertDisplay(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), displayId1, - true); + assertDisplay(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), PORT_B, true); // This should be public - assertDisplay(mListener.addedDisplays.get(2).getDisplayDeviceInfoLocked(), displayId2, - false); + assertDisplay(mListener.addedDisplays.get(2).getDisplayDeviceInfoLocked(), PORT_C, false); } /** @@ -137,11 +132,8 @@ public class LocalDisplayAdapterTest { */ @Test public void testPublicDisplaysForNoConfigLocalPrivateDisplayPorts() throws Exception { - // needs default one always - final long displayId0 = 0; - setUpDisplay(new DisplayConfig(displayId0, createDummyDisplayInfo())); - final long displayId1 = 1; - setUpDisplay(new DisplayConfig(displayId1, createDummyDisplayInfo())); + setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_A), createDummyDisplayInfo())); + setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_C), createDummyDisplayInfo())); updateAvailableDisplays(); // config_localPrivateDisplayPorts is null mAdapter.registerLocked(); @@ -149,35 +141,36 @@ public class LocalDisplayAdapterTest { waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); // This should be public - assertDisplay(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), displayId0, - false); + assertDisplay(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), PORT_A, false); // This should be public - assertDisplay(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), displayId1, - false); + assertDisplay(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), PORT_C, false); } - private void assertDisplay(DisplayDeviceInfo info, long expectedPort, boolean shouldBePrivate) { - DisplayAddress.Physical physical = (DisplayAddress.Physical) info.address; - assertNotNull(physical); - assertEquals(expectedPort, physical.getPort()); + private static void assertDisplay( + DisplayDeviceInfo info, int expectedPort, boolean shouldBePrivate) { + final DisplayAddress.Physical address = (DisplayAddress.Physical) info.address; + assertNotNull(address); + assertEquals((byte) expectedPort, address.getPort()); + assertEquals(DISPLAY_MODEL, address.getModel()); assertEquals(shouldBePrivate, (info.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0); } private class DisplayConfig { - public final long displayId; + public final DisplayAddress.Physical address; public final IBinder displayToken = new Binder(); public final SurfaceControl.PhysicalDisplayInfo displayInfo; - private DisplayConfig(long displayId, SurfaceControl.PhysicalDisplayInfo displayInfo) { - this.displayId = displayId | (0x1 << PHYSICAL_DISPLAY_ID_MODEL_SHIFT); + private DisplayConfig( + DisplayAddress.Physical address, SurfaceControl.PhysicalDisplayInfo displayInfo) { + this.address = address; this.displayInfo = displayInfo; } } private void setUpDisplay(DisplayConfig config) { - mDisplayIds.add(config.displayId); - doReturn(config.displayToken).when( - () -> SurfaceControl.getPhysicalDisplayToken(config.displayId)); + mAddresses.add(config.address); + doReturn(config.displayToken).when(() -> + SurfaceControl.getPhysicalDisplayToken(config.address.getPhysicalDisplayId())); doReturn(new SurfaceControl.PhysicalDisplayInfo[]{ config.displayInfo }).when(() -> SurfaceControl.getDisplayConfigs(config.displayToken)); @@ -192,16 +185,20 @@ public class LocalDisplayAdapterTest { } private void updateAvailableDisplays() { - long[] ids = new long[mDisplayIds.size()]; + long[] ids = new long[mAddresses.size()]; int i = 0; - for (long id : mDisplayIds) { - ids[i] = id; + for (DisplayAddress.Physical address : mAddresses) { + ids[i] = address.getPhysicalDisplayId(); i++; } doReturn(ids).when(() -> SurfaceControl.getPhysicalDisplayIds()); } - private SurfaceControl.PhysicalDisplayInfo createDummyDisplayInfo() { + private static DisplayAddress.Physical createDisplayAddress(int port) { + return DisplayAddress.fromPortAndModel((byte) port, DISPLAY_MODEL); + } + + private static SurfaceControl.PhysicalDisplayInfo createDummyDisplayInfo() { SurfaceControl.PhysicalDisplayInfo info = new SurfaceControl.PhysicalDisplayInfo(); info.density = 100; info.xDpi = 100; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java index d70e1648f719..96d9c476bcde 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java @@ -73,7 +73,7 @@ public class AccessibilityUserStateTest { @Mock private AccessibilityUserState.ServiceInfoChangeListener mMockListener; - @Mock private Context mContext; + @Mock private Context mMockContext; private MockContentResolver mMockResolver; @@ -85,11 +85,11 @@ public class AccessibilityUserStateTest { FakeSettingsProvider.clearSettingsProvider(); mMockResolver = new MockContentResolver(); mMockResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); - when(mContext.getContentResolver()).thenReturn(mMockResolver); + when(mMockContext.getContentResolver()).thenReturn(mMockResolver); when(mMockServiceInfo.getComponentName()).thenReturn(COMPONENT_NAME); when(mMockConnection.getServiceInfo()).thenReturn(mMockServiceInfo); - mUserState = new AccessibilityUserState(USER_ID, mContext, mMockListener); + mUserState = new AccessibilityUserState(USER_ID, mMockContext, mMockListener); } @After @@ -109,11 +109,11 @@ public class AccessibilityUserStateTest { mUserState.setInteractiveUiTimeoutLocked(30); mUserState.mEnabledServices.add(COMPONENT_NAME); mUserState.mTouchExplorationGrantedServices.add(COMPONENT_NAME); + mUserState.mAccessibilityShortcutKeyTargets.add(COMPONENT_NAME.flattenToString()); + mUserState.mAccessibilityButtonTargets.add(COMPONENT_NAME.flattenToString()); mUserState.setTouchExplorationEnabledLocked(true); mUserState.setDisplayMagnificationEnabledLocked(true); mUserState.setNavBarMagnificationEnabledLocked(true); - mUserState.setServiceAssignedToAccessibilityButtonLocked(COMPONENT_NAME); - mUserState.setNavBarMagnificationAssignedToAccessibilityButtonLocked(true); mUserState.setAutoclickEnabledLocked(true); mUserState.setUserNonInteractiveUiTimeoutLocked(30); mUserState.setUserInteractiveUiTimeoutLocked(30); @@ -128,11 +128,11 @@ public class AccessibilityUserStateTest { assertEquals(0, mUserState.getInteractiveUiTimeoutLocked()); assertTrue(mUserState.mEnabledServices.isEmpty()); assertTrue(mUserState.mTouchExplorationGrantedServices.isEmpty()); + assertTrue(mUserState.mAccessibilityShortcutKeyTargets.isEmpty()); + assertTrue(mUserState.mAccessibilityButtonTargets.isEmpty()); assertFalse(mUserState.isTouchExplorationEnabledLocked()); assertFalse(mUserState.isDisplayMagnificationEnabledLocked()); assertFalse(mUserState.isNavBarMagnificationEnabledLocked()); - assertNull(mUserState.getServiceAssignedToAccessibilityButtonLocked()); - assertFalse(mUserState.isNavBarMagnificationAssignedToAccessibilityButtonLocked()); assertFalse(mUserState.isAutoclickEnabledLocked()); assertEquals(0, mUserState.getUserNonInteractiveUiTimeoutLocked()); assertEquals(0, mUserState.getUserInteractiveUiTimeoutLocked()); @@ -287,6 +287,19 @@ public class AccessibilityUserStateTest { verify(mMockConnection).notifySoftKeyboardShowModeChangedLocked(eq(SHOW_MODE_HIDDEN)); } + @Test + public void isShortcutTargetInstalledLocked_returnTrue() { + mUserState.mInstalledServices.add(mMockServiceInfo); + assertTrue(mUserState.isShortcutTargetInstalledLocked(COMPONENT_NAME.flattenToString())); + } + + @Test + public void isShortcutTargetInstalledLocked_invalidTarget_returnFalse() { + final ComponentName invalidTarget = + new ComponentName("com.android.server.accessibility", "InvalidTarget"); + assertFalse(mUserState.isShortcutTargetInstalledLocked(invalidTarget.flattenToString())); + } + private int getSecureIntForUser(String key, int userId) { return Settings.Secure.getIntForUser(mMockResolver, key, -1, userId); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java index c5fb0bde579f..5f1f3083361b 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java @@ -23,7 +23,6 @@ import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManagerInternal; import android.content.pm.PackageManager; -import android.content.pm.UserInfo; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; @@ -39,6 +38,9 @@ import java.util.Map; import java.util.Set; public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { + + private static final String USER_TYPE_EMPTY = ""; + private DpmMockContext mContext; @Override @@ -52,9 +54,10 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { } public void testMigration() throws Exception { - final File user10dir = getServices().addUser(10, 0); - final File user11dir = getServices().addUser(11, UserInfo.FLAG_MANAGED_PROFILE); - getServices().addUser(12, 0); + final File user10dir = getServices().addUser(10, 0, USER_TYPE_EMPTY); + final File user11dir = getServices().addUser(11, 0, + UserManager.USER_TYPE_PROFILE_MANAGED); + getServices().addUser(12, 0, USER_TYPE_EMPTY); setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); setUpPackageManagerForAdmin(admin2, UserHandle.getUid(10, 123)); @@ -273,7 +276,8 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { // Test setting default restrictions for managed profile. public void testMigration3_managedProfileOwner() throws Exception { // Create a managed profile user. - final File user10dir = getServices().addUser(10, UserInfo.FLAG_MANAGED_PROFILE); + final File user10dir = getServices().addUser(10, 0, + UserManager.USER_TYPE_PROFILE_MANAGED); // Profile owner package for managed profile user. setUpPackageManagerForAdmin(admin1, UserHandle.getUid(10, 123)); // Set up fake UserManager to make it look like a managed profile. diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 06b8716c0926..43d8f927a57e 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -151,6 +151,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { private DpmMockContext mServiceContext; private DpmMockContext mAdmin1Context; public DevicePolicyManager dpm; + public DevicePolicyManager parentDpm; public DevicePolicyManagerServiceTestable dpms; /* @@ -240,6 +241,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm = new DevicePolicyManagerTestable(mContext, dpms); + parentDpm = new DevicePolicyManagerTestable(mServiceContext, dpms, + /* parentInstance= */true); + mContext.binder.restoreCallingIdentity(ident); } @@ -269,7 +273,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { anyString(), any(UserHandle.class)); // Add the first secondary user. - getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0); + getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, + UserManager.USER_TYPE_FULL_SECONDARY); } private void setAsProfileOwner(ComponentName admin) { @@ -330,7 +335,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testLoadAdminData_noAdmins() throws Exception { final int ANOTHER_USER_ID = 15; - getServices().addUser(ANOTHER_USER_ID, 0); + getServices().addUser(ANOTHER_USER_ID, 0, ""); initializeDpms(); @@ -477,7 +482,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int ANOTHER_USER_ID = 100; final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 20456); - getServices().addUser(ANOTHER_USER_ID, 0); // Add one more user. + getServices().addUser(ANOTHER_USER_ID, 0, ""); // Add one more user. // Set up pacakge manager for the other user. setUpPackageManagerForAdmin(admin2, ANOTHER_ADMIN_UID); @@ -1343,7 +1348,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int ANOTHER_USER_ID = 100; final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 456); - getServices().addUser(ANOTHER_USER_ID, 0); // Add one more user. + getServices().addUser(ANOTHER_USER_ID, 0, ""); // Add one more user. mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); @@ -1961,35 +1966,30 @@ public class DevicePolicyManagerTest extends DpmTestBase { // TODO Make sure restrictions are written to the file. } + // TODO: (b/138709470) test addUserRestriction as PO of an organization-owned device public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception { - setupProfileOwner(); + final int MANAGED_PROFILE_USER_ID = DpmMockContext.CALLER_USER_HANDLE; + final int MANAGED_PROFILE_ADMIN_UID = + UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID); + mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - final long ident = mServiceContext.binder.clearCallingIdentity(); - configureContextForAccess(mServiceContext, true); + addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); + configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE); - mServiceContext.binder.callingUid = - UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, - DpmMockContext.CALLER_MANAGED_PROVISIONING_UID); - try { - runAsCaller(mServiceContext, dpms, dpm -> { - dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1); - }); - } finally { - mServiceContext.binder.restoreCallingIdentity(ident); - } + when(getServices().userManager.getProfileParent(MANAGED_PROFILE_USER_ID)) + .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); - dpm.addUserRestriction(admin1, UserManager.DISALLOW_CONFIG_DATE_TIME); + parentDpm.setCameraDisabled(admin1, true); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( - eq(DpmMockContext.CALLER_USER_HANDLE), - MockUtils.checkUserRestrictions(UserManager.DISALLOW_CONFIG_DATE_TIME), + eq(UserHandle.USER_SYSTEM), + MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA), eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE)); reset(getServices().userManagerInternal); - dpm.setCameraDisabled(admin1, true); + parentDpm.setCameraDisabled(admin1, false); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( - eq(DpmMockContext.CALLER_USER_HANDLE), - MockUtils.checkUserRestrictions(UserManager.DISALLOW_CONFIG_DATE_TIME, - UserManager.DISALLOW_CAMERA), + eq(UserHandle.USER_SYSTEM), + MockUtils.checkUserRestrictions(), eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE)); reset(getServices().userManagerInternal); } @@ -3861,7 +3861,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Add a secondary user, it should never talk with. final int ANOTHER_USER_ID = 36; - getServices().addUser(ANOTHER_USER_ID, 0); + getServices().addUser(ANOTHER_USER_ID, 0, UserManager.USER_TYPE_FULL_SECONDARY); // Since the managed profile is not affiliated, they should not be allowed to talk to each // other. @@ -5206,8 +5206,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } public void testRevertProfileOwnership_adminAndProfileMigrated() throws Exception { - getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, UserInfo.FLAG_MANAGED_PROFILE, - UserHandle.USER_SYSTEM); + getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, + UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM); DpmTestUtils.writeInputStreamToFile( getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated), getProfileOwnerPoliciesFile()); @@ -5218,8 +5218,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } public void testRevertProfileOwnership_profileNotMigrated() throws Exception { - getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, UserInfo.FLAG_MANAGED_PROFILE, - UserHandle.USER_SYSTEM); + getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, + UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM); DpmTestUtils.writeInputStreamToFile( getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated), getProfileOwnerPoliciesFile()); @@ -5230,8 +5230,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } public void testRevertProfileOwnership_adminAndProfileNotMigrated() throws Exception { - getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, UserInfo.FLAG_MANAGED_PROFILE, - UserHandle.USER_SYSTEM); + getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, + UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM); DpmTestUtils.writeInputStreamToFile( getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_not_migrated), getProfileOwnerPoliciesFile()); @@ -5405,11 +5405,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY); setAsProfileOwner(admin1); - new DevicePolicyManagerTestable( - mServiceContext, - dpms, - /* parentInstance= */ true) - .getPasswordComplexity(); + parentDpm.getPasswordComplexity(); assertEquals(PASSWORD_COMPLEXITY_NONE, dpm.getPasswordComplexity()); } @@ -5685,7 +5681,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { private void addManagedProfile( ComponentName admin, int adminUid, ComponentName copyFromAdmin) throws Exception { final int userId = UserHandle.getUserId(adminUid); - getServices().addUser(userId, UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_SYSTEM); + getServices().addUser(userId, 0, UserManager.USER_TYPE_PROFILE_MANAGED, + UserHandle.USER_SYSTEM); mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS); setUpPackageManagerForFakeAdmin(admin, adminUid, copyFromAdmin); dpm.setActiveAdmin(admin, false, userId); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index 6a0d9265f594..7a2350eb4402 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -185,8 +185,8 @@ public class MockSystemServices { // Add the system user with a fake profile group already set up (this can happen in the real // world if a managed profile is added and then removed). - systemUserDataDir = - addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY, UserHandle.USER_SYSTEM); + systemUserDataDir = addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY, + UserManager.USER_TYPE_FULL_SYSTEM, UserHandle.USER_SYSTEM); // System user is always running. setUserRunning(UserHandle.USER_SYSTEM, true); @@ -208,26 +208,21 @@ public class MockSystemServices { mBroadcastReceivers.removeIf(r -> r.receiver == receiver); } - public File addUser(int userId, int flags) { - return addUser(userId, flags, UserInfo.NO_PROFILE_GROUP_ID); + public File addUser(int userId, int flags, String type) { + return addUser(userId, flags, type, UserInfo.NO_PROFILE_GROUP_ID); } - public File addUser(int userId, int flags, int profileGroupId) { + public File addUser(int userId, int flags, String type, int profileGroupId) { // Set up (default) UserInfo for CALLER_USER_HANDLE. final UserInfo uh = new UserInfo(userId, "user" + userId, flags); + + uh.userType = type; uh.profileGroupId = profileGroupId; when(userManager.getUserInfo(eq(userId))).thenReturn(uh); - mUserInfos.add(uh); when(userManager.getUsers()).thenReturn(mUserInfos); when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos); when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true); - when(userManager.getUserInfo(anyInt())).thenAnswer( - invocation -> { - final int userId1 = (int) invocation.getArguments()[0]; - return getUserInfo(userId1); - } - ); when(userManager.getProfileParent(anyInt())).thenAnswer( invocation -> { final int userId1 = (int) invocation.getArguments()[0]; @@ -308,7 +303,7 @@ public class MockSystemServices { */ public void addUsers(int... userIds) { for (final int userId : userIds) { - addUser(userId, 0); + addUser(userId, 0, ""); } } diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java new file mode 100644 index 000000000000..f6c4d3aa5f5f --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyFloat; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.hardware.Sensor; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; +import android.os.Handler; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +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; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class AutomaticBrightnessControllerTest { + + private static final int BRIGHTNESS_MIN = 1; + private static final int BRIGHTNESS_MAX = 255; + private static final int LIGHT_SENSOR_RATE = 20; + private static final int INITIAL_LIGHT_SENSOR_RATE = 20; + private static final int BRIGHTENING_LIGHT_DEBOUNCE_CONFIG = 0; + private static final int DARKENING_LIGHT_DEBOUNCE_CONFIG = 0; + private static final int SHORT_TERM_MODEL_TIMEOUT = 0; + private static final float DOZE_SCALE_FACTOR = 0.0f; + private static final boolean RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG = false; + + private Context mContext; + @Mock SensorManager mSensorManager; + @Mock BrightnessMappingStrategy mBrightnessMappingStrategy; + @Mock HysteresisLevels mAmbientBrightnessThresholds; + @Mock HysteresisLevels mScreenBrightnessThresholds; + @Mock PackageManager mPackageManager; + @Mock Handler mNoopHandler; + + private static final int LIGHT_SENSOR_WARMUP_TIME = 0; + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = InstrumentationRegistry.getContext(); + } + + private AutomaticBrightnessController setupController(Sensor lightSensor) { + AutomaticBrightnessController controller = new AutomaticBrightnessController( + new AutomaticBrightnessController.Injector() { + @Override + public Handler getBackgroundThreadHandler() { + return mNoopHandler; + } + }, + () -> { }, mContext.getMainLooper(), mSensorManager, lightSensor, + mBrightnessMappingStrategy, LIGHT_SENSOR_WARMUP_TIME, BRIGHTNESS_MIN, + BRIGHTNESS_MAX, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE, INITIAL_LIGHT_SENSOR_RATE, + BRIGHTENING_LIGHT_DEBOUNCE_CONFIG, DARKENING_LIGHT_DEBOUNCE_CONFIG, + RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG, mAmbientBrightnessThresholds, + mScreenBrightnessThresholds, SHORT_TERM_MODEL_TIMEOUT, mPackageManager); + controller.setLoggingEnabled(true); + + // Configure the brightness controller and grab an instance of the sensor listener, + // through which we can deliver fake (for test) sensor values. + controller.configure(true /* enable */, null /* configuration */, + 0 /* brightness */, false /* userChangedBrightness */, 0 /* adjustment */, + false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT); + + return controller; + } + + @Test + public void testNoHysteresisAtMinBrightness() throws Exception { + Sensor lightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor"); + AutomaticBrightnessController controller = setupController(lightSensor); + + ArgumentCaptor<SensorEventListener> listenerCaptor = + ArgumentCaptor.forClass(SensorEventListener.class); + verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(lightSensor), + eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); + SensorEventListener listener = listenerCaptor.getValue(); + + // Set up system to return 5 as a brightness value + float lux1 = 100.0f; + float normalizedBrightness1 = 0.02f; + when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux1)) + .thenReturn(lux1); + when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux1)) + .thenReturn(lux1); + when(mBrightnessMappingStrategy.getBrightness(eq(lux1), eq(null), anyInt())) + .thenReturn(normalizedBrightness1); + + // This is the important bit: When the new brightness is set, make sure the new + // brightening threshold is beyond the maximum brightness value...so that we can test that + // our threshold clamping works. + when(mScreenBrightnessThresholds.getBrighteningThreshold(5)).thenReturn(1.0f); + + // Send new sensor value and verify + listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux1)); + assertEquals(5, controller.getAutomaticScreenBrightness()); + + + // Set up system to return 255 as a brightness value + float lux2 = 10.0f; + float normalizedBrightness2 = 0.0f; + when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux2)) + .thenReturn(lux2); + when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux2)) + .thenReturn(lux2); + when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt())) + .thenReturn(normalizedBrightness2); + + // Send new sensor value and verify + listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux2)); + assertEquals(1, controller.getAutomaticScreenBrightness()); + } + + @Test + public void testNoHysteresisAtMaxBrightness() throws Exception { + Sensor lightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor"); + AutomaticBrightnessController controller = setupController(lightSensor); + + ArgumentCaptor<SensorEventListener> listenerCaptor = + ArgumentCaptor.forClass(SensorEventListener.class); + verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(lightSensor), + eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); + SensorEventListener listener = listenerCaptor.getValue(); + + // Set up system to return 250 as a brightness value + float lux1 = 100.0f; + float normalizedBrightness1 = 0.98f; + when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux1)) + .thenReturn(lux1); + when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux1)) + .thenReturn(lux1); + when(mBrightnessMappingStrategy.getBrightness(eq(lux1), eq(null), anyInt())) + .thenReturn(normalizedBrightness1); + + // This is the important bit: When the new brightness is set, make sure the new + // brightening threshold is beyond the maximum brightness value...so that we can test that + // our threshold clamping works. + when(mScreenBrightnessThresholds.getBrighteningThreshold(250)).thenReturn(260.0f); + + // Send new sensor value and verify + listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux1)); + assertEquals(250, controller.getAutomaticScreenBrightness()); + + + // Set up system to return 255 as a brightness value + float lux2 = 110.0f; + float normalizedBrightness2 = 1.0f; + when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux2)) + .thenReturn(lux2); + when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux2)) + .thenReturn(lux2); + when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt())) + .thenReturn(normalizedBrightness2); + + // Send new sensor value and verify + listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux2)); + assertEquals(255, controller.getAutomaticScreenBrightness()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java index 4742a73b17a8..8d5939ad6ef6 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.display; diff --git a/services/tests/servicestests/src/com/android/server/display/TestUtils.java b/services/tests/servicestests/src/com/android/server/display/TestUtils.java new file mode 100644 index 000000000000..859dfe3c3fa4 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/display/TestUtils.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.os.SystemClock; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public final class TestUtils { + + public static SensorEvent createSensorEvent(Sensor sensor, int lux) throws Exception { + final Constructor<SensorEvent> constructor = + SensorEvent.class.getDeclaredConstructor(int.class); + constructor.setAccessible(true); + final SensorEvent event = constructor.newInstance(1); + event.sensor = sensor; + event.values[0] = lux; + event.timestamp = SystemClock.elapsedRealtimeNanos(); + return event; + } + + + public static void setSensorType(Sensor sensor, int type, String strType) throws Exception { + Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE); + setter.setAccessible(true); + setter.invoke(sensor, type); + if (strType != null) { + Field f = sensor.getClass().getDeclaredField("mStringType"); + f.setAccessible(true); + f.set(sensor, strType); + } + } + + public static Sensor createSensor(int type, String strType) throws Exception { + Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor(); + constr.setAccessible(true); + Sensor sensor = constr.newInstance(); + setSensorType(sensor, type, strType); + return sensor; + } + +} diff --git a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java index acf2d0e700d4..2565ae3b4a85 100644 --- a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java +++ b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java @@ -16,31 +16,19 @@ package com.android.server.display.whitebalance; -import com.android.internal.R; -import com.android.server.display.utils.AmbientFilter; -import com.android.server.display.utils.AmbientFilterStubber; -import com.google.common.collect.ImmutableList; - import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.eq; -import org.mockito.stubbing.Answer; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; import android.content.ContextWrapper; import android.content.res.Resources; import android.content.res.TypedArray; import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Handler; import android.os.Looper; @@ -48,15 +36,22 @@ import android.util.TypedValue; import androidx.test.InstrumentationRegistry; +import com.android.internal.R; +import com.android.server.display.TestUtils; +import com.android.server.display.utils.AmbientFilter; +import com.android.server.display.utils.AmbientFilterStubber; + +import com.google.common.collect.ImmutableList; + import org.junit.Before; -import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.List; @RunWith(JUnit4.class) @@ -84,8 +79,8 @@ public final class AmbientLuxTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mLightSensor = createSensor(Sensor.TYPE_LIGHT, null); - mAmbientColorSensor = createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR); + mLightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, null); + mAmbientColorSensor = TestUtils.createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR); mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); mResourcesSpy = spy(mContextSpy.getResources()); when(mContextSpy.getResources()).thenReturn(mResourcesSpy); @@ -482,25 +477,6 @@ public final class AmbientLuxTest { } } - private void setSensorType(Sensor sensor, int type, String strType) throws Exception { - Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE); - setter.setAccessible(true); - setter.invoke(sensor, type); - if (strType != null) { - Field f = sensor.getClass().getDeclaredField("mStringType"); - f.setAccessible(true); - f.set(sensor, strType); - } - } - - private Sensor createSensor(int type, String strType) throws Exception { - Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor(); - constr.setAccessible(true); - Sensor sensor = constr.newInstance(); - setSensorType(sensor, type, strType); - return sensor; - } - private TypedArray createTypedArray() throws Exception { TypedArray mockArray = mock(TypedArray.class); return mockArray; diff --git a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientSensorTest.java b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientSensorTest.java index 6ff4f3b22b9c..3e3e535df986 100644 --- a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientSensorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientSensorTest.java @@ -28,15 +28,14 @@ import static org.mockito.Mockito.when; import android.content.ContextWrapper; import android.content.res.Resources; import android.hardware.Sensor; -import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Handler; import android.os.Looper; -import android.os.SystemClock; import androidx.test.InstrumentationRegistry; +import com.android.server.display.TestUtils; import com.android.server.display.whitebalance.AmbientSensor.AmbientBrightnessSensor; import com.android.server.display.whitebalance.AmbientSensor.AmbientColorTemperatureSensor; @@ -50,9 +49,6 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -73,8 +69,8 @@ public final class AmbientSensorTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mLightSensor = createSensor(Sensor.TYPE_LIGHT, null); - mAmbientColorSensor = createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR); + mLightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, null); + mAmbientColorSensor = TestUtils.createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR); mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); mResourcesSpy = spy(mContextSpy.getResources()); when(mContextSpy.getResources()).thenReturn(mResourcesSpy); @@ -96,7 +92,7 @@ public final class AmbientSensorTest { // There should be no issues when we callback the listener, even if there is no callback // set. SensorEventListener listener = captor.getValue(); - listener.onSensorChanged(createSensorEvent(mLightSensor, 100)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 100)); } @Test @@ -122,7 +118,7 @@ public final class AmbientSensorTest { verify(mSensorManagerMock).registerListener(captor.capture(), eq(mLightSensor), anyInt(), eq(mHandler)); SensorEventListener listener = captor.getValue(); - listener.onSensorChanged(createSensorEvent(mLightSensor, luxValue)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, luxValue)); assertTrue(changeSignal.await(5, TimeUnit.SECONDS)); assertEquals(luxValue, luxReturned[0]); } @@ -155,39 +151,8 @@ public final class AmbientSensorTest { verify(mSensorManagerMock).registerListener(captor.capture(), eq(mAmbientColorSensor), anyInt(), eq(mHandler)); SensorEventListener listener = captor.getValue(); - listener.onSensorChanged(createSensorEvent(mAmbientColorSensor, colorTempValue)); + listener.onSensorChanged(TestUtils.createSensorEvent(mAmbientColorSensor, colorTempValue)); assertTrue(changeSignal.await(5, TimeUnit.SECONDS)); assertEquals(colorTempValue, colorTempReturned[0]); } - - private SensorEvent createSensorEvent(Sensor sensor, int lux) throws Exception { - final Constructor<SensorEvent> constructor = - SensorEvent.class.getDeclaredConstructor(int.class); - constructor.setAccessible(true); - final SensorEvent event = constructor.newInstance(1); - event.sensor = sensor; - event.values[0] = lux; - event.timestamp = SystemClock.elapsedRealtimeNanos(); - return event; - } - - - private void setSensorType(Sensor sensor, int type, String strType) throws Exception { - Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE); - setter.setAccessible(true); - setter.invoke(sensor, type); - if (strType != null) { - Field f = sensor.getClass().getDeclaredField("mStringType"); - f.setAccessible(true); - f.set(sensor, strType); - } - } - - private Sensor createSensor(int type, String strType) throws Exception { - Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor(); - constr.setAccessible(true); - Sensor sensor = constr.newInstance(); - setSensorType(sensor, type, strType); - return sensor; - } } diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java new file mode 100644 index 000000000000..37ff06a18492 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity; + +import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; + +import static org.mockito.Mockito.verify; + +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.LocalServices; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** Unit test for {@link com.android.server.integrity.AppIntegrityManagerServiceImpl} */ +@RunWith(AndroidJUnit4.class) +public class AppIntegrityManagerServiceImplTest { + + @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); + + @Mock PackageManagerInternal mPackageManagerInternal; + + // under test + private AppIntegrityManagerServiceImpl mService; + + @Before + public void setup() { + LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); + + mService = new AppIntegrityManagerServiceImpl(InstrumentationRegistry.getContext()); + } + + @Test + public void integrityVerification_allow() { + int verificationId = 2; + Intent integrityVerificationIntent = new Intent(); + integrityVerificationIntent.setAction(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION); + integrityVerificationIntent.putExtra(EXTRA_VERIFICATION_ID, verificationId); + + // We cannot send the broadcast using the context since it is a protected broadcast and + // we will get a security exception. + mService.handleIntegrityVerification(integrityVerificationIntent); + + verify(mPackageManagerInternal) + .setIntegrityVerificationResult(verificationId, PackageManager.VERIFICATION_ALLOW); + } +} diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java new file mode 100644 index 000000000000..18b91b0b1009 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity.serializer; + +import static com.android.server.testutils.TestUtils.assertExpectException; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.integrity.AppInstallMetadata; +import android.content.integrity.AtomicFormula; +import android.content.integrity.CompoundFormula; +import android.content.integrity.Formula; +import android.content.integrity.Rule; + +import androidx.annotation.NonNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.Arrays; + +/** Unit tests for {@link RuleIndexTypeIdentifier}. */ +@RunWith(JUnit4.class) +public class RuleIndexTypeIdentifierTest { + + @Test + public void getIndexType_nullRule() { + Rule rule = null; + + assertExpectException( + IllegalArgumentException.class, + /* expectedExceptionMessageRegex= */ + "Indexing type cannot be determined for null rule.", + () -> RuleIndexTypeIdentifier.getIndexType(rule)); + } + + @Test + public void getIndexType_invalidFormula() { + Rule rule = new Rule(getInvalidFormula(), Rule.DENY); + + assertExpectException( + IllegalArgumentException.class, + /* expectedExceptionMessageRegex= */ "Invalid formula tag type.", + () -> RuleIndexTypeIdentifier.getIndexType(rule)); + } + + @Test + public void getIndexType_ruleContainingPackageNameFormula() { + String packageName = "com.test.app"; + String installerName = "com.test.installer"; + Rule rule = + new Rule( + new CompoundFormula( + CompoundFormula.AND, + Arrays.asList( + new AtomicFormula.StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, + packageName, + /* isHashedValue= */ false), + new AtomicFormula.StringAtomicFormula( + AtomicFormula.INSTALLER_NAME, + installerName, + /* isHashedValue= */ false))), + Rule.DENY); + + assertThat(RuleIndexTypeIdentifier.getIndexType(rule)) + .isEqualTo(RuleIndexTypeIdentifier.PACKAGE_NAME_INDEXED); + } + + @Test + public void getIndexType_ruleContainingAppCertificateFormula() { + String appCertificate = "cert1"; + String installerName = "com.test.installer"; + Rule rule = + new Rule( + new CompoundFormula( + CompoundFormula.AND, + Arrays.asList( + new AtomicFormula.StringAtomicFormula( + AtomicFormula.APP_CERTIFICATE, + appCertificate, + /* isHashedValue= */ false), + new AtomicFormula.StringAtomicFormula( + AtomicFormula.INSTALLER_NAME, + installerName, + /* isHashedValue= */ false))), + Rule.DENY); + + assertThat(RuleIndexTypeIdentifier.getIndexType(rule)) + .isEqualTo(RuleIndexTypeIdentifier.APP_CERTIFICATE_INDEXED); + } + + @Test + public void getIndexType_ruleWithUnindexedCompoundFormula() { + String installerCertificate = "cert1"; + String installerName = "com.test.installer"; + Rule rule = + new Rule( + new CompoundFormula( + CompoundFormula.AND, + Arrays.asList( + new AtomicFormula.StringAtomicFormula( + AtomicFormula.INSTALLER_CERTIFICATE, + installerCertificate, + /* isHashedValue= */ false), + new AtomicFormula.StringAtomicFormula( + AtomicFormula.INSTALLER_NAME, + installerName, + /* isHashedValue= */ false))), + Rule.DENY); + + assertThat(RuleIndexTypeIdentifier.getIndexType(rule)) + .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED); + } + + @Test + public void getIndexType_rulContainingCompoundFormulaWithIntAndBoolean() { + int appVersion = 12; + Rule rule = + new Rule( + new CompoundFormula( + CompoundFormula.AND, + Arrays.asList( + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, + /* booleanValue= */ true), + new AtomicFormula.IntAtomicFormula( + AtomicFormula.VERSION_CODE, + AtomicFormula.EQ, + appVersion))), + Rule.DENY); + + assertThat(RuleIndexTypeIdentifier.getIndexType(rule)) + .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED); + } + + @Test + public void getIndexType_negatedRuleContainingPackageNameFormula() { + String packageName = "com.test.app"; + String installerName = "com.test.installer"; + Rule rule = + new Rule( + new CompoundFormula( + CompoundFormula.NOT, + Arrays.asList( + new CompoundFormula( + CompoundFormula.AND, + Arrays.asList( + new AtomicFormula.StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, + packageName, + /* isHashedValue= */ false), + new AtomicFormula.StringAtomicFormula( + AtomicFormula.INSTALLER_NAME, + installerName, + /* isHashedValue= */ false))))), + Rule.DENY); + + assertThat(RuleIndexTypeIdentifier.getIndexType(rule)) + .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED); + } + + private Formula getInvalidFormula() { + return new Formula() { + @Override + public boolean isSatisfied(AppInstallMetadata appInstallMetadata) { + return false; + } + + @Override + public int getTag() { + return 4; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } + + @NonNull + @Override + protected Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + @Override + public String toString() { + return super.toString(); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + } + }; + } +} + diff --git a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java deleted file mode 100644 index d1c2fd0fa9dd..000000000000 --- a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.server.locksettings; - -import static com.android.server.testutils.TestUtils.assertExpectException; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.os.RemoteException; -import android.platform.test.annotations.Presubmit; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import com.android.internal.widget.LockscreenCredential; -import com.android.internal.widget.VerifyCredentialResponse; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; - -import java.util.ArrayList; - -/** - * Run the synthetic password tests with caching enabled. - * - * By default, those tests run without caching. Untrusted credential reset depends on caching so - * this class included those tests. - */ -@SmallTest -@Presubmit -@RunWith(AndroidJUnit4.class) -public class CachedSyntheticPasswordTests extends SyntheticPasswordTests { - - @Before - public void enableSpCache() throws Exception { - enableSpCaching(true); - } - - private void enableSpCaching(boolean enable) { - when(mDevicePolicyManagerInternal - .canUserHaveUntrustedCredentialReset(anyInt())).thenReturn(enable); - } - - @Test - public void testSyntheticPasswordClearCredentialUntrusted() throws RemoteException { - final LockscreenCredential password = newPassword("password"); - final LockscreenCredential newPassword = newPassword("newpassword"); - - initializeCredentialUnderSP(password, PRIMARY_USER_ID); - long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); - // clear password - mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, true); - assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); - - // set a new password - mService.setLockCredential(newPassword, nonePassword(), PRIMARY_USER_ID, - false); - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - newPassword, 0, PRIMARY_USER_ID) - .getResponseCode()); - assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); - } - - @Test - public void testSyntheticPasswordChangeCredentialUntrusted() throws RemoteException { - final LockscreenCredential password = newPassword("password"); - final LockscreenCredential newPassword = newPassword("newpassword"); - - initializeCredentialUnderSP(password, PRIMARY_USER_ID); - long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); - // Untrusted change password - mService.setLockCredential(newPassword, nonePassword(), PRIMARY_USER_ID, - true); - assertNotEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); - assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); - - // Verify the password - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - newPassword, 0, PRIMARY_USER_ID).getResponseCode()); - } - - @Test - public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException { - final LockscreenCredential password = newPassword("password"); - final LockscreenCredential newPassword = newPassword("newpassword"); - - initializeCredentialUnderSP(password, PRIMARY_USER_ID); - // Untrusted change password - mService.setLockCredential(newPassword, nonePassword(), PRIMARY_USER_ID, - true); - - // Verify the password - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - newPassword, 0, PRIMARY_USER_ID) - .getResponseCode()); - - // Ensure the same secret was passed each time - ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class); - verify(mAuthSecretService, atLeastOnce()).primaryUserCredential(secret.capture()); - assertEquals(1, secret.getAllValues().stream().distinct().count()); - } - - @Test - public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException { - final LockscreenCredential password = newPassword("password"); - final LockscreenCredential newPassword = newPassword("newpassword"); - - // Disable caching for this test - enableSpCaching(false); - - initializeCredentialUnderSP(password, PRIMARY_USER_ID); - flushHandlerTasks(); - - long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); - // Untrusted change password - assertExpectException( - IllegalStateException.class, - /* messageRegex= */ "Untrusted credential reset not possible without cached SP", - () -> mService.setLockCredential(newPassword, nonePassword(), - PRIMARY_USER_ID, true)); - assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); - - // Verify the new password doesn't work but the old one still does - assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential( - newPassword, 0, PRIMARY_USER_ID) - .getResponseCode()); - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - password, 0, PRIMARY_USER_ID) - .getResponseCode()); - } - -} diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java index 8c8edfad231f..abfda7725b7d 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java @@ -93,7 +93,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), sid); assertFalse(mService.setLockCredential(newPassword("newpwd"), newPassword("badpwd"), - PRIMARY_USER_ID, false)); + PRIMARY_USER_ID)); assertVerifyCredentials(PRIMARY_USER_ID, newPassword("password"), sid); } @@ -101,7 +101,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { public void testClearPasswordPrimaryUser() throws RemoteException { initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), 1234); assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"), - PRIMARY_USER_ID, false)); + PRIMARY_USER_ID)); assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); } @@ -111,7 +111,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { final LockscreenCredential firstUnifiedPassword = newPassword("pwd-1"); final LockscreenCredential secondUnifiedPassword = newPassword("pwd-2"); assertTrue(mService.setLockCredential(firstUnifiedPassword, - nonePassword(), PRIMARY_USER_ID, false)); + nonePassword(), PRIMARY_USER_ID)); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID); @@ -146,15 +146,14 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mStorageManager.setIgnoreBadUnlock(true); // Change primary password and verify that profile SID remains assertTrue(mService.setLockCredential( - secondUnifiedPassword, firstUnifiedPassword, PRIMARY_USER_ID, false)); + secondUnifiedPassword, firstUnifiedPassword, PRIMARY_USER_ID)); mStorageManager.setIgnoreBadUnlock(false); assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID)); // Clear unified challenge assertTrue(mService.setLockCredential(nonePassword(), - secondUnifiedPassword, PRIMARY_USER_ID, - false)); + secondUnifiedPassword, PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID)); @@ -166,7 +165,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { final LockscreenCredential profilePassword = newPassword("profile"); assertTrue(mService.setLockCredential(primaryPassword, nonePassword(), - PRIMARY_USER_ID, false)); + PRIMARY_USER_ID)); /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new * credential as part of verifyCredential() before the new credential is committed in * StorageManager. So we relax the check in our mock StorageManager to allow that. @@ -174,7 +173,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mStorageManager.setIgnoreBadUnlock(true); assertTrue(mService.setLockCredential(profilePassword, nonePassword(), - MANAGED_PROFILE_USER_ID, false)); + MANAGED_PROFILE_USER_ID)); mStorageManager.setIgnoreBadUnlock(false); final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); @@ -201,7 +200,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { // Change primary credential and make sure we don't affect profile mStorageManager.setIgnoreBadUnlock(true); assertTrue(mService.setLockCredential( - newPassword("pwd"), primaryPassword, PRIMARY_USER_ID, false)); + newPassword("pwd"), primaryPassword, PRIMARY_USER_ID)); mStorageManager.setIgnoreBadUnlock(false); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( profilePassword, 0, MANAGED_PROFILE_USER_ID) @@ -214,8 +213,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( newPassword("password"), nonePassword(), - PRIMARY_USER_ID, - false)); + PRIMARY_USER_ID)); verify(mRecoverableKeyStoreManager) .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, "password".getBytes(), @@ -228,8 +226,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( newPattern("12345"), nonePassword(), - MANAGED_PROFILE_USER_ID, - false)); + MANAGED_PROFILE_USER_ID)); verify(mRecoverableKeyStoreManager) .lockScreenSecretChanged(CREDENTIAL_TYPE_PATTERN, "12345".getBytes(), @@ -247,8 +244,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( newPassword("newPassword"), newPattern("12345"), - MANAGED_PROFILE_USER_ID, - false)); + MANAGED_PROFILE_USER_ID)); verify(mRecoverableKeyStoreManager) .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, "newPassword".getBytes(), @@ -263,8 +259,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( newPattern("12345"), nonePassword(), - PRIMARY_USER_ID, - false)); + PRIMARY_USER_ID)); verify(mRecoverableKeyStoreManager, never()) .lockScreenSecretChanged( @@ -284,8 +279,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( newCredential, oldCredential, - PRIMARY_USER_ID, - false)); + PRIMARY_USER_ID)); verify(mRecoverableKeyStoreManager) .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, newCredential.getCredential(), @@ -305,8 +299,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( nonePassword(), newPassword("oldPassword"), - PRIMARY_USER_ID, - false)); + PRIMARY_USER_ID)); verify(mRecoverableKeyStoreManager) .lockScreenSecretChanged(CREDENTIAL_TYPE_NONE, null, PRIMARY_USER_ID); @@ -322,7 +315,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { 1234); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); - mService.setLockCredential(nonePassword(), newPattern("123654"), PRIMARY_USER_ID, false); + mService.setLockCredential(nonePassword(), newPattern("123654"), PRIMARY_USER_ID); // Verify fingerprint is removed verify(mFingerprintManager).remove(any(), eq(PRIMARY_USER_ID), any()); @@ -343,8 +336,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( profilePassword, nonePassword(), - MANAGED_PROFILE_USER_ID, - false)); + MANAGED_PROFILE_USER_ID)); verify(mRecoverableKeyStoreManager) .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, profilePassword.getCredential(), @@ -390,8 +382,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( pattern, nonePassword(), - MANAGED_PROFILE_USER_ID, - false)); + MANAGED_PROFILE_USER_ID)); reset(mRecoverableKeyStoreManager); mService.verifyCredential(pattern, 1, MANAGED_PROFILE_USER_ID); @@ -426,7 +417,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { private void testCreateCredential(int userId, LockscreenCredential credential) throws RemoteException { - assertTrue(mService.setLockCredential(credential, nonePassword(), userId, false)); + assertTrue(mService.setLockCredential(credential, nonePassword(), userId)); assertVerifyCredentials(userId, credential, -1); } @@ -435,7 +426,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mHasSecureLockScreen = false; try { - mService.setLockCredential(credential, null, userId, false); + mService.setLockCredential(credential, null, userId); fail("An exception should have been thrown."); } catch (UnsupportedOperationException e) { // Success - the exception was expected. @@ -448,7 +439,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { LockscreenCredential oldCredential) throws RemoteException { final long sid = 1234; initializeStorageWithCredential(userId, oldCredential, sid); - assertTrue(mService.setLockCredential(newCredential, oldCredential, userId, false)); + assertTrue(mService.setLockCredential(newCredential, oldCredential, userId)); assertVerifyCredentials(userId, newCredential, sid); } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java index 27af9e2dfd6f..4b3f7b5d08ef 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java @@ -48,7 +48,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_setPin() { - mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID); assertEquals(CREDENTIAL_TYPE_PIN, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, @@ -57,7 +57,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_setPattern() { - mService.setLockCredential(newPattern("4321"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPattern("4321"), nonePassword(), PRIMARY_USER_ID); assertEquals(CREDENTIAL_TYPE_PATTERN, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, @@ -66,7 +66,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_setPassword() { - mService.setLockCredential(newPassword("4321"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPassword("4321"), nonePassword(), PRIMARY_USER_ID); assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, @@ -75,8 +75,8 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_changeCredential() { - mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID, false); - mService.setLockCredential(newPattern("5678"), newPassword("1234"), PRIMARY_USER_ID, false); + mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID); + mService.setLockCredential(newPattern("5678"), newPassword("1234"), PRIMARY_USER_ID); assertEquals(CREDENTIAL_TYPE_PATTERN, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, @@ -85,16 +85,16 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_removeCredential() { - mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID); assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP)); - mService.setLockCredential(nonePassword(), newPassword("1234"), PRIMARY_USER_ID, false); + mService.setLockCredential(nonePassword(), newPassword("1234"), PRIMARY_USER_ID); assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(USER_FRP)); } @Test public void testFrpCredential_cannotVerifyAfterProvsioning() { - mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID); mSettings.setDeviceProvisioned(true); assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, @@ -103,7 +103,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_legacyPinTypePersistentData() { - mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID); PersistentData data = mStorage.readPersistentDataBlock(); // Tweak the existing persistent data to make it look like one with legacy credential type assertEquals(CREDENTIAL_TYPE_PIN, data.payload[3]); @@ -119,7 +119,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_legacyPasswordTypePersistentData() { - mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID); PersistentData data = mStorage.readPersistentDataBlock(); // Tweak the existing persistent data to make it look like one with legacy credential type assertEquals(CREDENTIAL_TYPE_PASSWORD, data.payload[3]); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index 49858482fdf6..d6ef2d459769 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -106,7 +106,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { final LockscreenCredential password = newPassword("testPasswordMigration-password"); disableSyntheticPassword(); - assertTrue(mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID, false)); + assertTrue(mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID)); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); enableSyntheticPassword(); @@ -128,7 +128,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { protected void initializeCredentialUnderSP(LockscreenCredential password, int userId) throws RemoteException { enableSyntheticPassword(); - mService.setLockCredential(password, nonePassword(), userId, false); + mService.setLockCredential(password, nonePassword(), userId); assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(userId)); assertTrue(mService.isSyntheticPasswordBasedCredential(userId)); } @@ -140,7 +140,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { initializeCredentialUnderSP(password, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); - mService.setLockCredential(newPassword, password, PRIMARY_USER_ID, false); + mService.setLockCredential(newPassword, password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( newPassword, 0, PRIMARY_USER_ID) .getResponseCode()); @@ -170,12 +170,11 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { initializeCredentialUnderSP(password, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); // clear password - mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, false); + mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID); assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); // set a new password - mService.setLockCredential(badPassword, nonePassword(), - PRIMARY_USER_ID, false); + mService.setLockCredential(badPassword, nonePassword(), PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( badPassword, 0, PRIMARY_USER_ID) .getResponseCode()); @@ -188,7 +187,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential badPassword = newPassword("new"); initializeCredentialUnderSP(password, PRIMARY_USER_ID); - mService.setLockCredential(badPassword, password, PRIMARY_USER_ID, false); + mService.setLockCredential(badPassword, password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( badPassword, 0, PRIMARY_USER_ID) .getResponseCode()); @@ -245,7 +244,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException { LockscreenCredential password = newPassword("getASyntheticPassword"); initializeCredentialUnderSP(password, PRIMARY_USER_ID); - mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, false); + mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID); reset(mAuthSecretService); mService.onUnlockUser(PRIMARY_USER_ID); @@ -257,7 +256,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testManagedProfileUnifiedChallengeMigration() throws RemoteException { LockscreenCredential UnifiedPassword = newPassword("unified-pwd"); disableSyntheticPassword(); - mService.setLockCredential(UnifiedPassword, nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(UnifiedPassword, nonePassword(), PRIMARY_USER_ID); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID); @@ -292,9 +291,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential primaryPassword = newPassword("primary"); LockscreenCredential profilePassword = newPassword("profile"); disableSyntheticPassword(); - mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID, false); - mService.setLockCredential(profilePassword, nonePassword(), - MANAGED_PROFILE_USER_ID, false); + mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID); + mService.setLockCredential(profilePassword, nonePassword(), MANAGED_PROFILE_USER_ID); final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID); byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); @@ -404,7 +402,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode(); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.setLockCredential(pattern, password, PRIMARY_USER_ID, false); + mService.setLockCredential(pattern, password, PRIMARY_USER_ID); mLocalService.setLockCredentialWithToken(newPassword, handle, token, PRIMARY_USER_ID); @@ -433,7 +431,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { // initialized but the user currently has no password initializeCredentialUnderSP(newPassword("password"), PRIMARY_USER_ID); assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"), - PRIMARY_USER_ID, false)); + PRIMARY_USER_ID)); assertTrue(mService.isSyntheticPasswordBasedCredential(PRIMARY_USER_ID)); long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); @@ -449,7 +447,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential password = newPassword("password"); // Set up pre-SP user password disableSyntheticPassword(); - mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID); enableSyntheticPassword(); long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); @@ -507,11 +505,11 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { @Test public void testGetHashFactorPrimaryUser() throws RemoteException { LockscreenCredential password = newPassword("password"); - mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID); byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID); assertNotNull(hashFactor); - mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, false); + mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID); byte[] newHashFactor = mService.getHashFactor(nonePassword(), PRIMARY_USER_ID); assertNotNull(newHashFactor); // Hash factor should never change after password change/removal @@ -521,7 +519,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { @Test public void testGetHashFactorManagedProfileUnifiedChallenge() throws RemoteException { LockscreenCredential pattern = newPattern("1236"); - mService.setLockCredential(pattern, nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(pattern, nonePassword(), PRIMARY_USER_ID); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID)); } @@ -530,9 +528,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testGetHashFactorManagedProfileSeparateChallenge() throws RemoteException { LockscreenCredential primaryPassword = newPassword("primary"); LockscreenCredential profilePassword = newPassword("profile"); - mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID, false); - mService.setLockCredential(profilePassword, nonePassword(), - MANAGED_PROFILE_USER_ID, false); + mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID); + mService.setLockCredential(profilePassword, nonePassword(), MANAGED_PROFILE_USER_ID); assertNotNull( mService.getHashFactor(profilePassword, MANAGED_PROFILE_USER_ID)); } diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt new file mode 100644 index 000000000000..f45316fc74cd --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.om + +import android.content.pm.parsing.AndroidPackage +import android.net.Uri +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import org.testng.Assert.assertThrows +import test.util.mockThrowOnUnmocked +import test.util.whenever + +@RunWith(Parameterized::class) +class OverlayReferenceMapperTests { + + companion object { + private const val TARGET_PACKAGE_NAME = "com.test.target" + private const val OVERLAY_PACKAGE_NAME = "com.test.overlay" + private const val ACTOR_PACKAGE_NAME = "com.test.actor" + private const val ACTOR_NAME = "overlay://test/actorName" + + @JvmStatic + @Parameterized.Parameters(name = "deferRebuild {0}") + fun parameters() = arrayOf(true, false) + } + + private lateinit var mapper: OverlayReferenceMapper + + @JvmField + @Parameterized.Parameter(0) + var deferRebuild = false + + @Before + fun initMapper() { + mapper = mapper() + } + + @Test + fun targetWithOverlay() { + val target = mockTarget() + val overlay = mockOverlay() + val existing = mapper.addInOrder(overlay) + assertEmpty() + mapper.addInOrder(target, existing = existing) + assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay)) + mapper.remove(target) + assertEmpty() + } + + @Test + fun targetWithMultipleOverlays() { + val target = mockTarget() + val overlay0 = mockOverlay(0) + val overlay1 = mockOverlay(1) + mapper = mapper( + overlayToTargetToOverlayables = mapOf( + overlay0.packageName to mapOf( + target.packageName to target.overlayables.keys + ), + overlay1.packageName to mapOf( + target.packageName to target.overlayables.keys + ) + ) + ) + val existing = mapper.addInOrder(overlay0, overlay1) + assertEmpty() + mapper.addInOrder(target, existing = existing) + assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay0, overlay1)) + mapper.remove(overlay0) + assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay1)) + mapper.remove(target) + assertEmpty() + } + + @Test + fun targetWithoutOverlay() { + val target = mockTarget() + mapper.addInOrder(target) + assertMapping(ACTOR_PACKAGE_NAME to setOf(target)) + mapper.remove(target) + assertEmpty() + } + + @Test + fun overlayWithTarget() { + val target = mockTarget() + val overlay = mockOverlay() + val existing = mapper.addInOrder(target) + assertMapping(ACTOR_PACKAGE_NAME to setOf(target)) + mapper.addInOrder(overlay, existing = existing) + assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay)) + mapper.remove(overlay) + assertMapping(ACTOR_PACKAGE_NAME to setOf(target)) + } + + @Test + fun overlayWithMultipleTargets() { + val target0 = mockTarget(0) + val target1 = mockTarget(1) + val overlay = mockOverlay() + mapper = mapper( + overlayToTargetToOverlayables = mapOf( + overlay.packageName to mapOf( + target0.packageName to target0.overlayables.keys, + target1.packageName to target1.overlayables.keys + ) + ) + ) + mapper.addInOrder(target0, target1, overlay) + assertMapping(ACTOR_PACKAGE_NAME to setOf(target0, target1, overlay)) + mapper.remove(target0) + assertMapping(ACTOR_PACKAGE_NAME to setOf(target1, overlay)) + mapper.remove(target1) + assertEmpty() + } + + @Test + fun overlayWithoutTarget() { + val overlay = mockOverlay() + mapper.addInOrder(overlay) + // An overlay can only have visibility exposed through its target + assertEmpty() + mapper.remove(overlay) + assertEmpty() + } + + private fun OverlayReferenceMapper.addInOrder( + vararg pkgs: AndroidPackage, + existing: MutableMap<String, AndroidPackage> = mutableMapOf() + ) = pkgs.fold(existing) { map, pkg -> + addPkg(pkg, map) + map[pkg.packageName] = pkg + return@fold map + } + + private fun OverlayReferenceMapper.remove(pkg: AndroidPackage) = removePkg(pkg.packageName) + + private fun assertMapping(vararg pairs: Pair<String, Set<AndroidPackage>>) { + val expected = pairs.associate { it } + .mapValues { pair -> pair.value.map { it.packageName }.toSet() } + + // This validates the API exposed for querying the relationships + expected.forEach { (actorPkgName, expectedPkgNames) -> + expectedPkgNames.forEach { expectedPkgName -> + if (deferRebuild) { + assertThrows(IllegalStateException::class.java) { + mapper.isValidActor(expectedPkgName, actorPkgName) + } + mapper.rebuildIfDeferred() + deferRebuild = false + } + + assertThat(mapper.isValidActor(expectedPkgName, actorPkgName)).isTrue() + } + } + + // This asserts no other relationships are defined besides those tested above + assertThat(mapper.actorPkgToPkgs).containsExactlyEntriesIn(expected) + } + + private fun assertEmpty() = assertMapping() + + private fun mapper( + namedActors: Map<String, Map<String, String>> = Uri.parse(ACTOR_NAME).run { + mapOf(authority!! to mapOf(pathSegments.first() to ACTOR_PACKAGE_NAME)) + }, + overlayToTargetToOverlayables: Map<String, Map<String, Set<String>>> = mapOf( + mockOverlay().packageName to mapOf( + mockTarget().run { packageName to overlayables.keys } + ) + ) + ) = OverlayReferenceMapper(deferRebuild, object : OverlayReferenceMapper.Provider { + override fun getActorPkg(actor: String?) = + OverlayActorEnforcer.getPackageNameForActor(actor, namedActors).first + + override fun getTargetToOverlayables(pkg: AndroidPackage) = + overlayToTargetToOverlayables[pkg.packageName] ?: emptyMap() + }) + + private fun mockTarget(increment: Int = 0) = mockThrowOnUnmocked<AndroidPackage> { + whenever(packageName) { "$TARGET_PACKAGE_NAME$increment" } + whenever(overlayables) { mapOf("overlayableName$increment" to ACTOR_NAME) } + whenever(toString()) { "Package{$packageName}" } + } + + private fun mockOverlay(increment: Int = 0) = mockThrowOnUnmocked<AndroidPackage> { + whenever(packageName) { "$OVERLAY_PACKAGE_NAME$increment" } + whenever(overlayables) { emptyMap<String, String>() } + whenever(toString()) { "Package{$packageName}" } + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java index 178f38aac0b7..fb9c68a5b70d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java @@ -68,7 +68,7 @@ public class ApexManagerTest { @Before public void setUp() throws RemoteException { mContext = InstrumentationRegistry.getInstrumentation().getContext(); - mApexManager = new ApexManager.ApexManagerImpl(mContext, mApexService); + mApexManager = new ApexManager.ApexManagerImpl(mApexService); } @Test diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index f6fb6e23ccfb..82bbdcba5bc1 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -26,12 +26,20 @@ import static org.mockito.Mockito.when; import android.annotation.Nullable; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsingPackage; import android.os.Build; import android.os.Process; import android.util.ArrayMap; +import android.util.ArraySet; + +import androidx.annotation.NonNull; + +import com.android.server.om.OverlayReferenceMapper; import org.junit.Before; import org.junit.Test; @@ -40,56 +48,72 @@ import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + @RunWith(JUnit4.class) public class AppsFilterTest { private static final int DUMMY_CALLING_UID = 10345; private static final int DUMMY_TARGET_UID = 10556; + private static final int DUMMY_ACTOR_UID = 10656; + private static final int DUMMY_OVERLAY_UID = 10756; + private static final int DUMMY_ACTOR_TWO_UID = 10856; @Mock AppsFilter.FeatureConfig mFeatureConfigMock; private ArrayMap<String, PackageSetting> mExisting = new ArrayMap<>(); - private static PackageBuilder pkg(String packageName) { - return new PackageBuilder(packageName) - .setApplicationInfoTargetSdkVersion(Build.VERSION_CODES.R); + private static ParsingPackage pkg(String packageName) { + return PackageImpl.forParsing(packageName) + .setTargetSdkVersion(Build.VERSION_CODES.R); } - private static PackageBuilder pkg(String packageName, Intent... queries) { - return pkg(packageName).setQueriesIntents(queries); + private static ParsingPackage pkg(String packageName, Intent... queries) { + ParsingPackage pkg = pkg(packageName); + if (queries != null) { + for (Intent intent : queries) { + pkg.addQueriesIntent(intent); + } + } + return pkg; } - private static PackageBuilder pkg(String packageName, String... queriesPackages) { - return pkg(packageName).setQueriesPackages(queriesPackages); + private static ParsingPackage pkg(String packageName, String... queriesPackages) { + ParsingPackage pkg = pkg(packageName); + if (queriesPackages != null) { + for (String queryPackageName : queriesPackages) { + pkg.addQueriesPackage(queryPackageName); + } + } + return pkg; } - private static PackageBuilder pkg(String packageName, IntentFilter... filters) { - final ActivityInfo activityInfo = new ActivityInfo(); - final PackageBuilder packageBuilder = pkg(packageName).addActivity( - pkg -> new PackageParser.ParseComponentArgs(pkg, new String[1], 0, 0, 0, 0, 0, 0, - new String[]{packageName}, 0, 0, 0), activityInfo); + private static ParsingPackage pkg(String packageName, IntentFilter... filters) { + ParsedActivity activity = new ParsedActivity(); + activity.setPackageName(packageName); for (IntentFilter filter : filters) { - packageBuilder.addActivityIntentInfo(0 /* index */, activity -> { - final PackageParser.ActivityIntentInfo info = - new PackageParser.ActivityIntentInfo(activity); - if (filter.countActions() > 0) { - filter.actionsIterator().forEachRemaining(info::addAction); - } - if (filter.countCategories() > 0) { - filter.actionsIterator().forEachRemaining(info::addCategory); - } - if (filter.countDataAuthorities() > 0) { - filter.authoritiesIterator().forEachRemaining(info::addDataAuthority); - } - if (filter.countDataSchemes() > 0) { - filter.schemesIterator().forEachRemaining(info::addDataScheme); - } - activityInfo.exported = true; - return info; - }); + final ParsedActivityIntentInfo info = new ParsedActivityIntentInfo(packageName, null); + if (filter.countActions() > 0) { + filter.actionsIterator().forEachRemaining(info::addAction); + } + if (filter.countCategories() > 0) { + filter.actionsIterator().forEachRemaining(info::addAction); + } + if (filter.countDataAuthorities() > 0) { + filter.authoritiesIterator().forEachRemaining(info::addDataAuthority); + } + if (filter.countDataSchemes() > 0) { + filter.schemesIterator().forEachRemaining(info::addDataScheme); + } + activity.addIntent(info); + activity.exported = true; } - return packageBuilder; + + return pkg(packageName) + .addActivity(activity); } @Before @@ -98,14 +122,14 @@ public class AppsFilterTest { MockitoAnnotations.initMocks(this); when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true); - when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class))) + when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))) .thenReturn(true); } @Test public void testSystemReadyPropogates() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); appsFilter.onSystemReady(); verify(mFeatureConfigMock).onSystemReady(); } @@ -113,7 +137,8 @@ public class AppsFilterTest { @Test public void testQueriesAction_FilterMatches() { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_UID); @@ -126,7 +151,8 @@ public class AppsFilterTest { @Test public void testQueriesAction_NoMatchingAction_Filters() { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID); @@ -139,14 +165,15 @@ public class AppsFilterTest { @Test public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package", new Intent("TEST_ACTION")) - .setApplicationInfoTargetSdkVersion(Build.VERSION_CODES.P), + .setTargetSdkVersion(Build.VERSION_CODES.P), DUMMY_CALLING_UID); when(mFeatureConfigMock.packageIsEnabled(calling.pkg)).thenReturn(false); @@ -157,7 +184,8 @@ public class AppsFilterTest { @Test public void testNoQueries_Filters() { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID); @@ -170,7 +198,8 @@ public class AppsFilterTest { @Test public void testForceQueryable_DoesntFilter() { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_UID); @@ -183,7 +212,8 @@ public class AppsFilterTest { @Test public void testForceQueryableByDevice_SystemCaller_DoesntFilter() { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false); + new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null); + appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID, @@ -197,7 +227,8 @@ public class AppsFilterTest { @Test public void testForceQueryableByDevice_NonSystemCaller_Filters() { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false); + new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null); + appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID); @@ -212,7 +243,8 @@ public class AppsFilterTest { public void testSystemQueryable_DoesntFilter() { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, - true /* system force queryable */); + true /* system force queryable */, null); + appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID, @@ -226,7 +258,8 @@ public class AppsFilterTest { @Test public void testQueriesPackage_DoesntFilter() { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID); @@ -238,10 +271,11 @@ public class AppsFilterTest { @Test public void testNoQueries_FeatureOff_DoesntFilter() { - when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class))) + when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))) .thenReturn(false); final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage( appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID); @@ -254,20 +288,22 @@ public class AppsFilterTest { @Test public void testSystemUid_DoesntFilter() { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID); assertFalse(appsFilter.shouldFilterApplication(0, null, target, 0)); - assertFalse(appsFilter.shouldFilterApplication( - Process.FIRST_APPLICATION_UID - 1, null, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(Process.FIRST_APPLICATION_UID - 1, + null, target, 0)); } @Test public void testNonSystemUid_NoCallingSetting_Filters() { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID); @@ -278,7 +314,8 @@ public class AppsFilterTest { @Test public void testNoTargetPackage_filters() { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + appsFilter.onSystemReady(); PackageSetting target = new PackageSettingBuilder() .setName("com.some.package") @@ -292,30 +329,151 @@ public class AppsFilterTest { assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } + @Test + public void testActsOnTargetOfOverlay() { + final String actorName = "overlay://test/actorName"; + + ParsingPackage target = pkg("com.some.package.target") + .addOverlayable("overlayableName", actorName); + ParsingPackage overlay = pkg("com.some.package.overlay") + .setIsOverlay(true) + .setOverlayTarget(target.getPackageName()) + .setOverlayTargetName("overlayableName"); + ParsingPackage actor = pkg("com.some.package.actor"); + + final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, + new OverlayReferenceMapper.Provider() { + @Nullable + @Override + public String getActorPkg(String actorString) { + if (actorName.equals(actorString)) { + return actor.getPackageName(); + } + return null; + } + + @NonNull + @Override + public Map<String, Set<String>> getTargetToOverlayables( + @NonNull AndroidPackage pkg) { + if (overlay.getPackageName().equals(pkg.getPackageName())) { + Map<String, Set<String>> map = new ArrayMap<>(); + Set<String> set = new ArraySet<>(); + set.add(overlay.getOverlayTargetName()); + map.put(overlay.getOverlayTarget(), set); + return map; + } + return Collections.emptyMap(); + } + }); + appsFilter.onSystemReady(); + + PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID); + PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID); + PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_UID); + + // Actor can see both target and overlay + assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting, + targetSetting, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting, + overlaySetting, 0)); + + // But target/overlay can't see each other + assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting, + overlaySetting, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting, + targetSetting, 0)); + + // And can't see the actor + assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting, + actorSetting, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting, + actorSetting, 0)); + } + + @Test + public void testActsOnTargetOfOverlayThroughSharedUser() { + final String actorName = "overlay://test/actorName"; + + ParsingPackage target = pkg("com.some.package.target") + .addOverlayable("overlayableName", actorName); + ParsingPackage overlay = pkg("com.some.package.overlay") + .setIsOverlay(true) + .setOverlayTarget(target.getPackageName()) + .setOverlayTargetName("overlayableName"); + ParsingPackage actorOne = pkg("com.some.package.actor.one"); + ParsingPackage actorTwo = pkg("com.some.package.actor.two"); + + final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, + new OverlayReferenceMapper.Provider() { + @Nullable + @Override + public String getActorPkg(String actorString) { + // Only actorOne is mapped as a valid actor + if (actorName.equals(actorString)) { + return actorOne.getPackageName(); + } + return null; + } + + @NonNull + @Override + public Map<String, Set<String>> getTargetToOverlayables( + @NonNull AndroidPackage pkg) { + if (overlay.getPackageName().equals(pkg.getPackageName())) { + Map<String, Set<String>> map = new ArrayMap<>(); + Set<String> set = new ArraySet<>(); + set.add(overlay.getOverlayTargetName()); + map.put(overlay.getOverlayTarget(), set); + return map; + } + return Collections.emptyMap(); + } + }); + appsFilter.onSystemReady(); + + PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID); + PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID); + PackageSetting actorOneSetting = simulateAddPackage(appsFilter, actorOne, DUMMY_ACTOR_UID); + PackageSetting actorTwoSetting = simulateAddPackage(appsFilter, actorTwo, + DUMMY_ACTOR_TWO_UID); + + SharedUserSetting actorSharedSetting = new SharedUserSetting("actorSharedUser", + actorOneSetting.pkgFlags, actorOneSetting.pkgPrivateFlags); + actorSharedSetting.addPackage(actorOneSetting); + actorSharedSetting.addPackage(actorTwoSetting); + + // actorTwo can see both target and overlay + assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting, + targetSetting, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting, + overlaySetting, 0)); + } + private interface WithSettingBuilder { PackageSettingBuilder withBuilder(PackageSettingBuilder builder); } private PackageSetting simulateAddPackage(AppsFilter filter, - PackageBuilder newPkgBuilder, int appId) { + ParsingPackage newPkgBuilder, int appId) { return simulateAddPackage(filter, newPkgBuilder, appId, null); } private PackageSetting simulateAddPackage(AppsFilter filter, - PackageBuilder newPkgBuilder, int appId, @Nullable WithSettingBuilder action) { - PackageParser.Package newPkg = newPkgBuilder.build(); + ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action) { + AndroidPackage newPkg = newPkgBuilder.hideAsParsed().hideAsFinal(); final PackageSettingBuilder settingBuilder = new PackageSettingBuilder() .setPackage(newPkg) .setAppId(appId) - .setName(newPkg.packageName) + .setName(newPkg.getPackageName()) .setCodePath("/") .setResourcePath("/") .setPVersionCode(1L); final PackageSetting setting = (action == null ? settingBuilder : action.withBuilder(settingBuilder)).build(); filter.addPackage(setting, mExisting); - mExisting.put(newPkg.packageName, setting); + mExisting.put(newPkg.getPackageName(), setting); return setting; } diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java index fec3267c2649..0273a1c5d86e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java @@ -19,17 +19,17 @@ package com.android.server.pm; import android.content.pm.PackageParser; import android.content.pm.Signature; +import android.test.AndroidTestCase; import android.util.ArrayMap; import android.util.ArraySet; import android.util.LongSparseArray; + import com.android.internal.util.ArrayUtils; import java.io.File; import java.io.IOException; -import java.security.cert.CertificateException; import java.security.PublicKey; - -import android.test.AndroidTestCase; +import java.security.cert.CertificateException; public class KeySetManagerServiceTest extends AndroidTestCase { @@ -39,7 +39,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { public PackageSetting generateFakePackageSetting(String name) { return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"), new File(mContext.getCacheDir(), "fakeResPath"), "", "", "", - "", 1, 0, 0, null, null, 0 /*sharedUserId*/, null /*usesStaticLibraries*/, + "", 1, 0, 0, 0 /*sharedUserId*/, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); } diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java deleted file mode 100644 index c38672cfc93c..000000000000 --- a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.pm; - -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageParser; - -import com.android.internal.util.ArrayUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; - -class PackageBuilder { - final PackageParser.Package mPkg; - - PackageBuilder(String packageName) { - mPkg = new PackageParser.Package(packageName); - } - - PackageBuilder setApplicationInfoCodePath(String codePath) { - mPkg.applicationInfo.setCodePath(codePath); - return this; - } - - PackageBuilder setApplicationInfoResourcePath(String resourcePath) { - mPkg.applicationInfo.setResourcePath(resourcePath); - return this; - } - - PackageBuilder setCodePath(String codePath) { - mPkg.codePath = codePath; - return this; - } - - PackageBuilder setBaseCodePath(String baseCodePath) { - mPkg.baseCodePath = baseCodePath; - return this; - } - - PackageBuilder addUsesStaticLibrary(String name, long version) { - mPkg.usesStaticLibraries = ArrayUtils.add(mPkg.usesStaticLibraries, name); - mPkg.usesStaticLibrariesVersions = - ArrayUtils.appendLong(mPkg.usesStaticLibrariesVersions, version); - return this; - } - - PackageBuilder setApplicationInfoNativeLibraryRootDir(String dir) { - mPkg.applicationInfo.nativeLibraryRootDir = dir; - return this; - } - - PackageBuilder setStaticSharedLib(String staticSharedLibName, long staticSharedLibVersion) { - mPkg.staticSharedLibVersion = staticSharedLibVersion; - mPkg.staticSharedLibName = staticSharedLibName; - return this; - } - - PackageBuilder setManifestPackageName(String manifestPackageName) { - mPkg.manifestPackageName = manifestPackageName; - return this; - } - - PackageBuilder setVersionCodeMajor(int versionCodeMajor) { - mPkg.mVersionCodeMajor = versionCodeMajor; - return this; - } - - PackageBuilder setVersionCode(int versionCode) { - mPkg.mVersionCode = versionCode; - return this; - } - - PackageBuilder addSplitCodePath(String splitCodePath) { - mPkg.splitCodePaths = - ArrayUtils.appendElement(String.class, mPkg.splitCodePaths, splitCodePath); - return this; - } - - PackageBuilder setApplicationInfoVolumeUuid(String volumeUuid) { - mPkg.applicationInfo.volumeUuid = volumeUuid; - return this; - } - - PackageBuilder addLibraryName(String libraryName) { - mPkg.libraryNames = ArrayUtils.add(mPkg.libraryNames, libraryName); - return this; - } - - PackageBuilder setRealPackageName(String realPackageName) { - mPkg.mRealPackage = realPackageName; - return this; - } - - PackageBuilder setCpuAbiOVerride(String cpuAbiOverride) { - mPkg.cpuAbiOverride = cpuAbiOverride; - return this; - } - - PackageBuilder addPermissionRequest(String permissionName) { - mPkg.requestedPermissions.add(permissionName); - return this; - } - - PackageParser.Package build() { - return mPkg; - } - - public PackageBuilder addApplicationInfoFlag(int flag) { - mPkg.applicationInfo.flags |= flag; - return this; - } - - public PackageBuilder setApplicationInfoTargetSdkVersion(int versionCode) { - mPkg.applicationInfo.targetSdkVersion = versionCode; - return this; - } - - public PackageBuilder setQueriesIntents(Collection<Intent> queriesIntents) { - mPkg.mQueriesIntents = new ArrayList<>(queriesIntents); - return this; - } - - public PackageBuilder setQueriesIntents(Intent... intents) { - return setQueriesIntents(Arrays.asList(intents)); - } - - public PackageBuilder setQueriesPackages(Collection<String> queriesPackages) { - mPkg.mQueriesPackages = new ArrayList<>(queriesPackages); - return this; - } - - public PackageBuilder setQueriesPackages(String... queriesPackages) { - return setQueriesPackages(Arrays.asList(queriesPackages)); - } - - public PackageBuilder setForceQueryable(boolean forceQueryable) { - mPkg.mForceQueryable = forceQueryable; - return this; - } - - public interface ParseComponentArgsCreator { - PackageParser.ParseComponentArgs create(PackageParser.Package pkg); - } - - public PackageBuilder addActivity(ParseComponentArgsCreator argsCreator, ActivityInfo info) { - mPkg.activities.add(new PackageParser.Activity(argsCreator.create(mPkg), info)); - return this; - } - - public interface ActivityIntentInfoCreator { - PackageParser.ActivityIntentInfo create(PackageParser.Activity activity); - } - - public PackageBuilder addActivityIntentInfo( - int activityIndex, ActivityIntentInfoCreator creator) { - final PackageParser.Activity activity = mPkg.activities.get(activityIndex); - activity.intents.add(creator.create(activity)); - return this; - } -} diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java index 0a310d193675..85840e135909 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java @@ -87,7 +87,7 @@ public class PackageManagerServiceTest { setting = new PackageSetting("name", "realName", new File("codePath"), new File("resourcePath"), "legacyNativeLibraryPathString", "primaryCpuAbiString", "secondaryCpuAbiString", - "cpuAbiOverrideString", 0, 0, 0, "parentPackageName", null, 0, + "cpuAbiOverrideString", 0, 0, 0, 0, null, null); pri.populateUsers(new int[] { 1, 2, 3, 4, 5 diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 1106be2d5f6b..8329227360e7 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -403,10 +403,6 @@ public class PackageManagerSettingsTests { private static final String PACKAGE_NAME = "com.android.bar"; private static final String REAL_PACKAGE_NAME = "com.android.foo"; - private static final String PARENT_PACKAGE_NAME = "com.android.bar.parent"; - private static final String CHILD_PACKAGE_NAME_01 = "com.android.bar.child01"; - private static final String CHILD_PACKAGE_NAME_02 = "com.android.bar.child02"; - private static final String CHILD_PACKAGE_NAME_03 = "com.android.bar.child03"; private static final File INITIAL_CODE_PATH = new File(InstrumentationRegistry.getContext().getFilesDir(), "com.android.bar-1"); private static final File UPDATED_CODE_PATH = @@ -416,10 +412,6 @@ public class PackageManagerSettingsTests { @Test public void testPackageStateCopy01() { - final List<String> childPackageNames = new ArrayList<>(); - childPackageNames.add(CHILD_PACKAGE_NAME_01); - childPackageNames.add(CHILD_PACKAGE_NAME_02); - childPackageNames.add(CHILD_PACKAGE_NAME_03); final PackageSetting origPkgSetting01 = new PackageSetting( PACKAGE_NAME, REAL_PACKAGE_NAME, @@ -432,8 +424,6 @@ public class PackageManagerSettingsTests { INITIAL_VERSION_CODE, ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN, - PARENT_PACKAGE_NAME, - childPackageNames, 0, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -443,10 +433,6 @@ public class PackageManagerSettingsTests { @Test public void testPackageStateCopy02() { - final List<String> childPackageNames = new ArrayList<>(); - childPackageNames.add(CHILD_PACKAGE_NAME_01); - childPackageNames.add(CHILD_PACKAGE_NAME_02); - childPackageNames.add(CHILD_PACKAGE_NAME_03); final PackageSetting origPkgSetting01 = new PackageSetting( PACKAGE_NAME /*pkgName*/, REAL_PACKAGE_NAME /*realPkgName*/, @@ -459,8 +445,6 @@ public class PackageManagerSettingsTests { INITIAL_VERSION_CODE, ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN, - PARENT_PACKAGE_NAME, - childPackageNames, 0, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -476,8 +460,6 @@ public class PackageManagerSettingsTests { UPDATED_VERSION_CODE, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, - null /*parentPkgName*/, - null /*childPkgNames*/, 0, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -505,7 +487,6 @@ public class PackageManagerSettingsTests { "armeabi" /*secondaryCpuAbi*/, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -539,7 +520,6 @@ public class PackageManagerSettingsTests { "armeabi" /*secondaryCpuAbi*/, ApplicationInfo.FLAG_SYSTEM /*pkgFlags*/, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED /*pkgPrivateFlags*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -579,7 +559,6 @@ public class PackageManagerSettingsTests { "armeabi" /*secondaryCpuAbi*/, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -612,8 +591,6 @@ public class PackageManagerSettingsTests { false /*allowInstall*/, false /*instantApp*/, false /*virtualPreload*/, - null /*parentPkgName*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -653,8 +630,6 @@ public class PackageManagerSettingsTests { true /*allowInstall*/, false /*instantApp*/, false /*virtualPreload*/, - null /*parentPkgName*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -700,8 +675,6 @@ public class PackageManagerSettingsTests { false /*allowInstall*/, false /*instantApp*/, false /*virtualPreload*/, - null /*parentPkgName*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -744,8 +717,6 @@ public class PackageManagerSettingsTests { false /*allowInstall*/, false /*instantApp*/, false /*virtualPreload*/, - null /*parentPkgName*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -802,9 +773,6 @@ public class PackageManagerSettingsTests { private void verifySettingCopy(PackageSetting origPkgSetting, PackageSetting testPkgSetting) { assertThat(origPkgSetting, is(not(testPkgSetting))); assertThat(origPkgSetting.appId, is(testPkgSetting.appId)); - // different but equal objects - assertNotSame(origPkgSetting.childPackageNames, testPkgSetting.childPackageNames); - assertThat(origPkgSetting.childPackageNames, is(testPkgSetting.childPackageNames)); assertSame(origPkgSetting.codePath, testPkgSetting.codePath); assertThat(origPkgSetting.codePath, is(testPkgSetting.codePath)); assertSame(origPkgSetting.codePathString, testPkgSetting.codePathString); @@ -828,8 +796,6 @@ public class PackageManagerSettingsTests { // mOldCodePaths is _not_ copied // assertNotSame(origPkgSetting.mOldCodePaths, testPkgSetting.mOldCodePaths); // assertThat(origPkgSetting.mOldCodePaths, is(not(testPkgSetting.mOldCodePaths))); - assertSame(origPkgSetting.parentPackageName, testPkgSetting.parentPackageName); - assertThat(origPkgSetting.parentPackageName, is(testPkgSetting.parentPackageName)); assertSame(origPkgSetting.pkg, testPkgSetting.pkg); // No equals() method for this object // assertThat(origPkgSetting.pkg, is(testPkgSetting.pkg)); @@ -881,8 +847,6 @@ public class PackageManagerSettingsTests { INITIAL_VERSION_CODE, pkgFlags, 0 /*privateFlags*/, - null /*parentPackageName*/, - null /*childPackageNames*/, sharedUserId, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -901,8 +865,6 @@ public class PackageManagerSettingsTests { INITIAL_VERSION_CODE, 0, 0 /*privateFlags*/, - null /*parentPackageName*/, - null /*childPackageNames*/, 0, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java index e33d8ca66ed0..56ac7c55443e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java @@ -15,35 +15,49 @@ */ package com.android.server.pm; -import static android.content.res.Resources.ID_NULL; - +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ConfigurationInfo; import android.content.pm.FeatureGroupInfo; import android.content.pm.FeatureInfo; -import android.content.pm.InstrumentationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageParser; +import android.content.pm.PackageUserState; import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; +import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.PackageInfoUtils; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.ParsingPackage; import android.os.Bundle; import android.os.Parcel; import android.platform.test.annotations.Presubmit; -import android.util.ArrayMap; import android.util.ArraySet; import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.ArrayUtils; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -57,6 +71,7 @@ import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -64,6 +79,9 @@ import java.util.Set; @RunWith(AndroidJUnit4.class) @MediumTest public class PackageParserTest { + // TODO(b/135203078): Update this test with all fields and validate equality. Initial change + // was just migrating to new interfaces. Consider adding actual equals() methods. + @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); @@ -79,12 +97,12 @@ public class PackageParserTest { @Test public void testParse_noCache() throws Exception { PackageParser pp = new CachePackageNameParser(); - PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, + ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); assertNotNull(pkg); pp.setCacheDir(mTmpDir); - pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, + pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); assertNotNull(pkg); @@ -99,27 +117,27 @@ public class PackageParserTest { pp.setCacheDir(mTmpDir); // The first parse will write this package to the cache. - pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); + pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); // Now attempt to parse the package again, should return the // cached result. - PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, + ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); - assertEquals("cache_android", pkg.packageName); + assertEquals("cache_android", pkg.getPackageName()); // Try again, with useCaches == false, shouldn't return the parsed // result. - pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); - assertEquals("android", pkg.packageName); + pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); + assertEquals("android", pkg.getPackageName()); // We haven't set a cache directory here : the parse should still succeed, // just not using the cached results. pp = new CachePackageNameParser(); - pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); - assertEquals("android", pkg.packageName); + pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); + assertEquals("android", pkg.getPackageName()); - pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); - assertEquals("android", pkg.packageName); + pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); + assertEquals("android", pkg.getPackageName()); } @Test @@ -127,14 +145,14 @@ public class PackageParserTest { PackageParser pp = new PackageParser(); pp.setCacheDir(mTmpDir); - PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, - true /* useCaches */); + ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, + true /* useCaches */); Parcel p = Parcel.obtain(); pkg.writeToParcel(p, 0 /* flags */); p.setDataPosition(0); - PackageParser.Package deserialized = new PackageParser.Package(p); + ParsedPackage deserialized = new PackageImpl(p); assertPackagesEqual(pkg, deserialized); } @@ -143,46 +161,52 @@ public class PackageParserTest { @SmallTest @Presubmit public void test_roundTripKnownFields() throws Exception { - PackageParser.Package pkg = new PackageParser.Package("foo"); + ParsingPackage pkg = PackageImpl.forParsing("foo"); setKnownFields(pkg); Parcel p = Parcel.obtain(); pkg.writeToParcel(p, 0 /* flags */); p.setDataPosition(0); - PackageParser.Package deserialized = new PackageParser.Package(p); + ParsedPackage deserialized = new PackageImpl(p); assertAllFieldsExist(deserialized); } @Test public void test_stringInterning() throws Exception { - PackageParser.Package pkg = new PackageParser.Package("foo"); + ParsingPackage pkg = PackageImpl.forParsing("foo"); setKnownFields(pkg); Parcel p = Parcel.obtain(); pkg.writeToParcel(p, 0 /* flags */); p.setDataPosition(0); - PackageParser.Package deserialized = new PackageParser.Package(p); + ParsingPackage deserialized = new PackageImpl(p); p.setDataPosition(0); - PackageParser.Package deserialized2 = new PackageParser.Package(p); - - assertSame(deserialized.packageName, deserialized2.packageName); - assertSame(deserialized.applicationInfo.permission, - deserialized2.applicationInfo.permission); - assertSame(deserialized.requestedPermissions.get(0), - deserialized2.requestedPermissions.get(0)); - assertSame(deserialized.protectedBroadcasts.get(0), - deserialized2.protectedBroadcasts.get(0)); - assertSame(deserialized.usesLibraries.get(0), - deserialized2.usesLibraries.get(0)); - assertSame(deserialized.usesOptionalLibraries.get(0), - deserialized2.usesOptionalLibraries.get(0)); - assertSame(deserialized.mVersionName, deserialized2.mVersionName); - assertSame(deserialized.mSharedUserId, deserialized2.mSharedUserId); - } + ParsingPackage deserialized2 = new PackageImpl(p); + assertSame(deserialized.getPackageName(), deserialized2.getPackageName()); + assertSame(deserialized.getPermission(), + deserialized2.getPermission()); + assertSame(deserialized.getRequestedPermissions().get(0), + deserialized2.getRequestedPermissions().get(0)); + + List<String> protectedBroadcastsOne = new ArrayList<>(1); + protectedBroadcastsOne.addAll(deserialized.getProtectedBroadcasts()); + + List<String> protectedBroadcastsTwo = new ArrayList<>(1); + protectedBroadcastsTwo.addAll(deserialized2.getProtectedBroadcasts()); + + assertSame(protectedBroadcastsOne.get(0), protectedBroadcastsTwo.get(0)); + + assertSame(deserialized.getUsesLibraries().get(0), + deserialized2.getUsesLibraries().get(0)); + assertSame(deserialized.getUsesOptionalLibraries().get(0), + deserialized2.getUsesOptionalLibraries().get(0)); + assertSame(deserialized.getVersionName(), deserialized2.getVersionName()); + assertSame(deserialized.getSharedUserId(), deserialized2.getSharedUserId()); + } /** * A trivial subclass of package parser that only caches the package name, and throws away @@ -190,107 +214,111 @@ public class PackageParserTest { */ public static class CachePackageNameParser extends PackageParser { @Override - public byte[] toCacheEntry(Package pkg) { - return ("cache_" + pkg.packageName).getBytes(StandardCharsets.UTF_8); + public byte[] toCacheEntry(ParsedPackage pkg) { + return ("cache_" + pkg.getPackageName()).getBytes(StandardCharsets.UTF_8); } @Override - public Package fromCacheEntry(byte[] cacheEntry) { - return new Package(new String(cacheEntry, StandardCharsets.UTF_8)); + public ParsedPackage fromCacheEntry(byte[] cacheEntry) { + return PackageImpl.forParsing(new String(cacheEntry, StandardCharsets.UTF_8)) + .hideAsParsed(); } } // NOTE: The equality assertions below are based on code autogenerated by IntelliJ. - public static void assertPackagesEqual(PackageParser.Package a, PackageParser.Package b) { - assertEquals(a.baseRevisionCode, b.baseRevisionCode); - assertEquals(a.baseHardwareAccelerated, b.baseHardwareAccelerated); - assertEquals(a.mVersionCode, b.mVersionCode); - assertEquals(a.mSharedUserLabel, b.mSharedUserLabel); - assertEquals(a.mPreferredOrder, b.mPreferredOrder); - assertEquals(a.installLocation, b.installLocation); - assertEquals(a.coreApp, b.coreApp); - assertEquals(a.mRequiredForAllUsers, b.mRequiredForAllUsers); - assertEquals(a.mCompileSdkVersion, b.mCompileSdkVersion); - assertEquals(a.mCompileSdkVersionCodename, b.mCompileSdkVersionCodename); - assertEquals(a.use32bitAbi, b.use32bitAbi); - assertEquals(a.packageName, b.packageName); - assertTrue(Arrays.equals(a.splitNames, b.splitNames)); - assertEquals(a.volumeUuid, b.volumeUuid); - assertEquals(a.codePath, b.codePath); - assertEquals(a.baseCodePath, b.baseCodePath); - assertTrue(Arrays.equals(a.splitCodePaths, b.splitCodePaths)); - assertTrue(Arrays.equals(a.splitRevisionCodes, b.splitRevisionCodes)); - assertTrue(Arrays.equals(a.splitFlags, b.splitFlags)); - assertTrue(Arrays.equals(a.splitPrivateFlags, b.splitPrivateFlags)); - assertApplicationInfoEqual(a.applicationInfo, b.applicationInfo); - - assertEquals(a.permissions.size(), b.permissions.size()); - for (int i = 0; i < a.permissions.size(); ++i) { - assertPermissionsEqual(a.permissions.get(i), b.permissions.get(i)); - assertSame(a.permissions.get(i).owner, a); - assertSame(b.permissions.get(i).owner, b); + public static void assertPackagesEqual(AndroidPackage a, AndroidPackage b) { + assertEquals(a.getBaseRevisionCode(), b.getBaseRevisionCode()); + assertEquals(a.isBaseHardwareAccelerated(), b.isBaseHardwareAccelerated()); + assertEquals(a.getVersionCode(), b.getVersionCode()); + assertEquals(a.getSharedUserLabel(), b.getSharedUserLabel()); + assertEquals(a.getPreferredOrder(), b.getPreferredOrder()); + assertEquals(a.getInstallLocation(), b.getInstallLocation()); + assertEquals(a.isCoreApp(), b.isCoreApp()); + assertEquals(a.isRequiredForAllUsers(), b.isRequiredForAllUsers()); + assertEquals(a.getCompileSdkVersion(), b.getCompileSdkVersion()); + assertEquals(a.getCompileSdkVersionCodeName(), b.getCompileSdkVersionCodeName()); + assertEquals(a.isUse32BitAbi(), b.isUse32BitAbi()); + assertEquals(a.getPackageName(), b.getPackageName()); + assertArrayEquals(a.getSplitNames(), b.getSplitNames()); + assertEquals(a.getVolumeUuid(), b.getVolumeUuid()); + assertEquals(a.getCodePath(), b.getCodePath()); + assertEquals(a.getBaseCodePath(), b.getBaseCodePath()); + assertArrayEquals(a.getSplitCodePaths(), b.getSplitCodePaths()); + assertArrayEquals(a.getSplitRevisionCodes(), b.getSplitRevisionCodes()); + assertArrayEquals(a.getSplitFlags(), b.getSplitFlags()); + + PackageInfo aInfo = PackageInfoUtils.generate(a, new int[]{}, 0, 0, 0, + Collections.emptySet(), new PackageUserState(), 0); + PackageInfo bInfo = PackageInfoUtils.generate(b, new int[]{}, 0, 0, 0, + Collections.emptySet(), new PackageUserState(), 0); + assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo); + + assertEquals(ArrayUtils.size(a.getPermissions()), ArrayUtils.size(b.getPermissions())); + for (int i = 0; i < ArrayUtils.size(a.getPermissions()); ++i) { + assertPermissionsEqual(a.getPermissions().get(i), b.getPermissions().get(i)); } - assertEquals(a.permissionGroups.size(), b.permissionGroups.size()); - for (int i = 0; i < a.permissionGroups.size(); ++i) { - assertPermissionGroupsEqual(a.permissionGroups.get(i), b.permissionGroups.get(i)); + assertEquals(ArrayUtils.size(a.getPermissionGroups()), + ArrayUtils.size(b.getPermissionGroups())); + for (int i = 0; i < a.getPermissionGroups().size(); ++i) { + assertPermissionGroupsEqual(a.getPermissionGroups().get(i), + b.getPermissionGroups().get(i)); } - assertEquals(a.activities.size(), b.activities.size()); - for (int i = 0; i < a.activities.size(); ++i) { - assertActivitiesEqual(a.activities.get(i), b.activities.get(i)); + assertEquals(ArrayUtils.size(a.getActivities()), ArrayUtils.size(b.getActivities())); + for (int i = 0; i < ArrayUtils.size(a.getActivities()); ++i) { + assertActivitiesEqual(a, a.getActivities().get(i), b, b.getActivities().get(i)); } - assertEquals(a.receivers.size(), b.receivers.size()); - for (int i = 0; i < a.receivers.size(); ++i) { - assertActivitiesEqual(a.receivers.get(i), b.receivers.get(i)); + assertEquals(ArrayUtils.size(a.getReceivers()), ArrayUtils.size(b.getReceivers())); + for (int i = 0; i < ArrayUtils.size(a.getReceivers()); ++i) { + assertActivitiesEqual(a, a.getReceivers().get(i), b, b.getReceivers().get(i)); } - assertEquals(a.providers.size(), b.providers.size()); - for (int i = 0; i < a.providers.size(); ++i) { - assertProvidersEqual(a.providers.get(i), b.providers.get(i)); + assertEquals(ArrayUtils.size(a.getProviders()), ArrayUtils.size(b.getProviders())); + for (int i = 0; i < ArrayUtils.size(a.getProviders()); ++i) { + assertProvidersEqual(a, a.getProviders().get(i), b, b.getProviders().get(i)); } - assertEquals(a.services.size(), b.services.size()); - for (int i = 0; i < a.services.size(); ++i) { - assertServicesEqual(a.services.get(i), b.services.get(i)); + assertEquals(ArrayUtils.size(a.getServices()), ArrayUtils.size(b.getServices())); + for (int i = 0; i < ArrayUtils.size(a.getServices()); ++i) { + assertServicesEqual(a, a.getServices().get(i), b, b.getServices().get(i)); } - assertEquals(a.instrumentation.size(), b.instrumentation.size()); - for (int i = 0; i < a.instrumentation.size(); ++i) { - assertInstrumentationEqual(a.instrumentation.get(i), b.instrumentation.get(i)); + assertEquals(ArrayUtils.size(a.getInstrumentations()), + ArrayUtils.size(b.getInstrumentations())); + for (int i = 0; i < ArrayUtils.size(a.getInstrumentations()); ++i) { + assertInstrumentationEqual(a.getInstrumentations().get(i), + b.getInstrumentations().get(i)); } - assertEquals(a.requestedPermissions, b.requestedPermissions); - assertEquals(a.protectedBroadcasts, b.protectedBroadcasts); - assertEquals(a.parentPackage, b.parentPackage); - assertEquals(a.childPackages, b.childPackages); - assertEquals(a.libraryNames, b.libraryNames); - assertEquals(a.usesLibraries, b.usesLibraries); - assertEquals(a.usesOptionalLibraries, b.usesOptionalLibraries); - assertTrue(Arrays.equals(a.usesLibraryFiles, b.usesLibraryFiles)); - assertEquals(a.mOriginalPackages, b.mOriginalPackages); - assertEquals(a.mRealPackage, b.mRealPackage); - assertEquals(a.mAdoptPermissions, b.mAdoptPermissions); - assertBundleApproximateEquals(a.mAppMetaData, b.mAppMetaData); - assertEquals(a.mVersionName, b.mVersionName); - assertEquals(a.mSharedUserId, b.mSharedUserId); - assertTrue(Arrays.equals(a.mSigningDetails.signatures, b.mSigningDetails.signatures)); - assertTrue(Arrays.equals(a.mLastPackageUsageTimeInMills, b.mLastPackageUsageTimeInMills)); - assertEquals(a.mExtras, b.mExtras); - assertEquals(a.mRestrictedAccountType, b.mRestrictedAccountType); - assertEquals(a.mRequiredAccountType, b.mRequiredAccountType); - assertEquals(a.mOverlayTarget, b.mOverlayTarget); - assertEquals(a.mOverlayTargetName, b.mOverlayTargetName); - assertEquals(a.mOverlayCategory, b.mOverlayCategory); - assertEquals(a.mOverlayPriority, b.mOverlayPriority); - assertEquals(a.mOverlayIsStatic, b.mOverlayIsStatic); - assertEquals(a.mSigningDetails.publicKeys, b.mSigningDetails.publicKeys); - assertEquals(a.mUpgradeKeySets, b.mUpgradeKeySets); - assertEquals(a.mKeySetMapping, b.mKeySetMapping); - assertEquals(a.cpuAbiOverride, b.cpuAbiOverride); - assertTrue(Arrays.equals(a.restrictUpdateHash, b.restrictUpdateHash)); + assertEquals(a.getRequestedPermissions(), b.getRequestedPermissions()); + assertEquals(a.getProtectedBroadcasts(), b.getProtectedBroadcasts()); + assertEquals(a.getLibraryNames(), b.getLibraryNames()); + assertEquals(a.getUsesLibraries(), b.getUsesLibraries()); + assertEquals(a.getUsesOptionalLibraries(), b.getUsesOptionalLibraries()); + assertArrayEquals(a.getUsesLibraryFiles(), b.getUsesLibraryFiles()); + assertEquals(a.getOriginalPackages(), b.getOriginalPackages()); + assertEquals(a.getRealPackage(), b.getRealPackage()); + assertEquals(a.getAdoptPermissions(), b.getAdoptPermissions()); + assertBundleApproximateEquals(a.getAppMetaData(), b.getAppMetaData()); + assertEquals(a.getVersionName(), b.getVersionName()); + assertEquals(a.getSharedUserId(), b.getSharedUserId()); + assertArrayEquals(a.getSigningDetails().signatures, b.getSigningDetails().signatures); + assertArrayEquals(a.getLastPackageUsageTimeInMills(), b.getLastPackageUsageTimeInMills()); + assertEquals(a.getRestrictedAccountType(), b.getRestrictedAccountType()); + assertEquals(a.getRequiredAccountType(), b.getRequiredAccountType()); + assertEquals(a.getOverlayTarget(), b.getOverlayTarget()); + assertEquals(a.getOverlayTargetName(), b.getOverlayTargetName()); + assertEquals(a.getOverlayCategory(), b.getOverlayCategory()); + assertEquals(a.getOverlayPriority(), b.getOverlayPriority()); + assertEquals(a.isOverlayIsStatic(), b.isOverlayIsStatic()); + assertEquals(a.getSigningDetails().publicKeys, b.getSigningDetails().publicKeys); + assertEquals(a.getUpgradeKeySets(), b.getUpgradeKeySets()); + assertEquals(a.getKeySetMapping(), b.getKeySetMapping()); + assertEquals(a.getCpuAbiOverride(), b.getCpuAbiOverride()); + assertArrayEquals(a.getRestrictUpdateHash(), b.getRestrictUpdateHash()); } private static void assertBundleApproximateEquals(Bundle a, Bundle b) { @@ -305,10 +333,10 @@ public class PackageParserTest { assertEquals(a.toString(), b.toString()); } - private static void assertComponentsEqual(PackageParser.Component<?> a, - PackageParser.Component<?> b) { + private static void assertComponentsEqual(ParsedComponent<?> a, + ParsedComponent<?> b) { assertEquals(a.className, b.className); - assertBundleApproximateEquals(a.metaData, b.metaData); + assertBundleApproximateEquals(a.getMetaData(), b.getMetaData()); assertEquals(a.getComponentName(), b.getComponentName()); if (a.intents != null && b.intents != null) { @@ -318,80 +346,102 @@ public class PackageParserTest { } for (int i = 0; i < a.intents.size(); ++i) { - PackageParser.IntentInfo aIntent = a.intents.get(i); - PackageParser.IntentInfo bIntent = b.intents.get(i); + ParsedIntentInfo aIntent = a.intents.get(i); + ParsedIntentInfo bIntent = b.intents.get(i); assertEquals(aIntent.hasDefault, bIntent.hasDefault); assertEquals(aIntent.labelRes, bIntent.labelRes); assertEquals(aIntent.nonLocalizedLabel, bIntent.nonLocalizedLabel); assertEquals(aIntent.icon, bIntent.icon); - assertEquals(aIntent.logo, bIntent.logo); - assertEquals(aIntent.banner, bIntent.banner); - assertEquals(aIntent.preferred, bIntent.preferred); } } - private static void assertPermissionsEqual(PackageParser.Permission a, - PackageParser.Permission b) { + private static void assertPermissionsEqual(ParsedPermission a, + ParsedPermission b) { assertComponentsEqual(a, b); assertEquals(a.tree, b.tree); // Verify basic flags in PermissionInfo to make sure they're consistent. We don't perform // a full structural equality here because the code that serializes them isn't parser // specific and is tested elsewhere. - assertEquals(a.info.protectionLevel, b.info.protectionLevel); - assertEquals(a.info.group, b.info.group); - assertEquals(a.info.flags, b.info.flags); + assertEquals(a.getProtection(), b.getProtection()); + assertEquals(a.getGroup(), b.getGroup()); + assertEquals(a.flags, b.flags); - if (a.group != null && b.group != null) { - assertPermissionGroupsEqual(a.group, b.group); - } else if (a.group != null || b.group != null) { + if (a.parsedPermissionGroup != null && b.parsedPermissionGroup != null) { + assertPermissionGroupsEqual(a.parsedPermissionGroup, b.parsedPermissionGroup); + } else if (a.parsedPermissionGroup != null || b.parsedPermissionGroup != null) { throw new AssertionError(); } } - private static void assertInstrumentationEqual(PackageParser.Instrumentation a, - PackageParser.Instrumentation b) { + private static void assertInstrumentationEqual(ParsedInstrumentation a, + ParsedInstrumentation b) { assertComponentsEqual(a, b); // Sanity check for InstrumentationInfo. - assertEquals(a.info.targetPackage, b.info.targetPackage); - assertEquals(a.info.targetProcesses, b.info.targetProcesses); - assertEquals(a.info.sourceDir, b.info.sourceDir); - assertEquals(a.info.publicSourceDir, b.info.publicSourceDir); + assertEquals(a.getTargetPackage(), b.getTargetPackage()); + assertEquals(a.getTargetProcesses(), b.getTargetProcesses()); } - private static void assertServicesEqual(PackageParser.Service a, PackageParser.Service b) { + private static void assertServicesEqual( + AndroidPackage aPkg, + ParsedService a, + AndroidPackage bPkg, + ParsedService b + ) { assertComponentsEqual(a, b); // Sanity check for ServiceInfo. - assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo); - assertEquals(a.info.name, b.info.name); + ServiceInfo aInfo = PackageInfoUtils.generateServiceInfo(aPkg, a, 0, new PackageUserState(), + 0); + ServiceInfo bInfo = PackageInfoUtils.generateServiceInfo(bPkg, b, 0, new PackageUserState(), + 0); + assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo); + assertEquals(a.getName(), b.getName()); } - private static void assertProvidersEqual(PackageParser.Provider a, PackageParser.Provider b) { + private static void assertProvidersEqual( + AndroidPackage aPkg, + ParsedProvider a, + AndroidPackage bPkg, + ParsedProvider b + ) { assertComponentsEqual(a, b); // Sanity check for ProviderInfo - assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo); - assertEquals(a.info.name, b.info.name); + ProviderInfo aInfo = PackageInfoUtils.generateProviderInfo(aPkg, a, 0, + new PackageUserState(), 0); + ProviderInfo bInfo = PackageInfoUtils.generateProviderInfo(bPkg, b, 0, + new PackageUserState(), 0); + assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo); + assertEquals(a.getName(), b.getName()); } - private static void assertActivitiesEqual(PackageParser.Activity a, PackageParser.Activity b) { + private static void assertActivitiesEqual( + AndroidPackage aPkg, + ParsedActivity a, + AndroidPackage bPkg, + ParsedActivity b + ) { assertComponentsEqual(a, b); // Sanity check for ActivityInfo. - assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo); - assertEquals(a.info.name, b.info.name); + ActivityInfo aInfo = PackageInfoUtils.generateActivityInfo(aPkg, a, 0, + new PackageUserState(), 0); + ActivityInfo bInfo = PackageInfoUtils.generateActivityInfo(bPkg, b, 0, + new PackageUserState(), 0); + assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo); + assertEquals(a.getName(), b.getName()); } - private static void assertPermissionGroupsEqual(PackageParser.PermissionGroup a, - PackageParser.PermissionGroup b) { + private static void assertPermissionGroupsEqual(ParsedPermissionGroup a, + ParsedPermissionGroup b) { assertComponentsEqual(a, b); // Sanity check for PermissionGroupInfo. - assertEquals(a.info.name, b.info.name); - assertEquals(a.info.descriptionRes, b.info.descriptionRes); + assertEquals(a.getName(), b.getName()); + assertEquals(a.descriptionRes, b.descriptionRes); } private static void assertApplicationInfoEqual(ApplicationInfo a, ApplicationInfo that) { @@ -424,11 +474,11 @@ public class PackageParserTest { assertEquals(a.scanPublicSourceDir, that.scanPublicSourceDir); assertEquals(a.sourceDir, that.sourceDir); assertEquals(a.publicSourceDir, that.publicSourceDir); - assertTrue(Arrays.equals(a.splitSourceDirs, that.splitSourceDirs)); - assertTrue(Arrays.equals(a.splitPublicSourceDirs, that.splitPublicSourceDirs)); - assertTrue(Arrays.equals(a.resourceDirs, that.resourceDirs)); + assertArrayEquals(a.splitSourceDirs, that.splitSourceDirs); + assertArrayEquals(a.splitPublicSourceDirs, that.splitPublicSourceDirs); + assertArrayEquals(a.resourceDirs, that.resourceDirs); assertEquals(a.seInfo, that.seInfo); - assertTrue(Arrays.equals(a.sharedLibraryFiles, that.sharedLibraryFiles)); + assertArrayEquals(a.sharedLibraryFiles, that.sharedLibraryFiles); assertEquals(a.dataDir, that.dataDir); assertEquals(a.deviceProtectedDataDir, that.deviceProtectedDataDir); assertEquals(a.credentialProtectedDataDir, that.credentialProtectedDataDir); @@ -439,132 +489,93 @@ public class PackageParserTest { assertEquals(a.secondaryCpuAbi, that.secondaryCpuAbi); } - public static void setKnownFields(PackageParser.Package pkg) { - pkg.baseRevisionCode = 100; - pkg.baseHardwareAccelerated = true; - pkg.mVersionCode = 100; - pkg.mSharedUserLabel = 100; - pkg.mPreferredOrder = 100; - pkg.installLocation = 100; - pkg.coreApp = true; - pkg.mRequiredForAllUsers = true; - pkg.use32bitAbi = true; - pkg.packageName = "foo"; - pkg.splitNames = new String[] { "foo2" }; - pkg.volumeUuid = "foo3"; - pkg.codePath = "foo4"; - pkg.baseCodePath = "foo5"; - pkg.splitCodePaths = new String[] { "foo6" }; - pkg.splitRevisionCodes = new int[] { 100 }; - pkg.splitFlags = new int[] { 100 }; - pkg.splitPrivateFlags = new int[] { 100 }; - pkg.applicationInfo = new ApplicationInfo(); - - pkg.permissions.add(new PackageParser.Permission(pkg, (String) null)); - pkg.permissionGroups.add(new PackageParser.PermissionGroup(pkg, ID_NULL, ID_NULL, ID_NULL)); - - final PackageParser.ParseComponentArgs dummy = new PackageParser.ParseComponentArgs( - pkg, new String[1], 0, 0, 0, 0, 0, 0, null, 0, 0, 0); - - pkg.activities.add(new PackageParser.Activity(dummy, new ActivityInfo())); - pkg.receivers.add(new PackageParser.Activity(dummy, new ActivityInfo())); - pkg.providers.add(new PackageParser.Provider(dummy, new ProviderInfo())); - pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo())); - pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo())); - pkg.requestedPermissions.add("foo7"); - pkg.implicitPermissions.add("foo25"); - - pkg.protectedBroadcasts = new ArrayList<>(); - pkg.protectedBroadcasts.add("foo8"); - - pkg.parentPackage = new PackageParser.Package("foo9"); - - pkg.childPackages = new ArrayList<>(); - pkg.childPackages.add(new PackageParser.Package("bar")); - - pkg.staticSharedLibName = "foo23"; - pkg.staticSharedLibVersion = 100; - pkg.usesStaticLibraries = new ArrayList<>(); - pkg.usesStaticLibraries.add("foo23"); - pkg.usesStaticLibrariesCertDigests = new String[1][]; - pkg.usesStaticLibrariesCertDigests[0] = new String[] { "digest" }; - pkg.usesStaticLibrariesVersions = new long[] { 100 }; - - pkg.libraryNames = new ArrayList<>(); - pkg.libraryNames.add("foo10"); - - pkg.usesLibraries = new ArrayList<>(); - pkg.usesLibraries.add("foo11"); - - pkg.usesOptionalLibraries = new ArrayList<>(); - pkg.usesOptionalLibraries.add("foo12"); - - pkg.usesLibraryFiles = new String[] { "foo13"}; - - pkg.usesLibraryInfos = new ArrayList<>(); - pkg.usesLibraryInfos.add( - new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null)); - - pkg.mOriginalPackages = new ArrayList<>(); - pkg.mOriginalPackages.add("foo14"); - - pkg.mRealPackage = "foo15"; - - pkg.mAdoptPermissions = new ArrayList<>(); - pkg.mAdoptPermissions.add("foo16"); - - pkg.mAppMetaData = new Bundle(); - pkg.mVersionName = "foo17"; - pkg.mSharedUserId = "foo18"; - pkg.mSigningDetails = - new PackageParser.SigningDetails( - new Signature[] { new Signature(new byte[16]) }, - 2, - new ArraySet<>(), - null); - pkg.mExtras = new Bundle(); - pkg.mRestrictedAccountType = "foo19"; - pkg.mRequiredAccountType = "foo20"; - pkg.mOverlayTarget = "foo21"; - pkg.mOverlayPriority = 100; - pkg.mUpgradeKeySets = new ArraySet<>(); - pkg.mKeySetMapping = new ArrayMap<>(); - pkg.cpuAbiOverride = "foo22"; - pkg.restrictUpdateHash = new byte[16]; - - pkg.preferredActivityFilters = new ArrayList<>(); - pkg.preferredActivityFilters.add(new PackageParser.ActivityIntentInfo( - new PackageParser.Activity(dummy, new ActivityInfo()))); - - pkg.configPreferences = new ArrayList<>(); - pkg.configPreferences.add(new ConfigurationInfo()); - - pkg.reqFeatures = new ArrayList<>(); - pkg.reqFeatures.add(new FeatureInfo()); - - pkg.featureGroups = new ArrayList<>(); - pkg.featureGroups.add(new FeatureGroupInfo()); - - pkg.mCompileSdkVersionCodename = "foo23"; - pkg.mCompileSdkVersion = 100; - pkg.mVersionCodeMajor = 100; - - pkg.mOverlayCategory = "foo24"; - pkg.mOverlayIsStatic = true; - pkg.mOverlayTargetName = "foo26"; - - pkg.baseHardwareAccelerated = true; - pkg.coreApp = true; - pkg.mRequiredForAllUsers = true; - pkg.visibleToInstantApps = true; - pkg.use32bitAbi = true; - pkg.mForceQueryable = true; - pkg.mQueriesPackages = new ArrayList<>(Arrays.asList("foo27")); - pkg.mQueriesIntents = new ArrayList<>(Arrays.asList(new Intent("foo28"))); + public static void setKnownFields(ParsingPackage pkg) { + Bundle bundle = new Bundle(); + bundle.putString("key", "value"); + + ParsedPermission permission = new ParsedPermission(); + permission.parsedPermissionGroup = new ParsedPermissionGroup(); + + pkg.setBaseRevisionCode(100) + .setBaseHardwareAccelerated(true) + .setSharedUserLabel(100) + .setPreferredOrder(100) + .setInstallLocation(100) + .setRequiredForAllUsers(true) + .asSplit( + new String[]{"foo2"}, + new String[]{"foo6"}, + new int[]{100}, + null + ) + .setUse32BitAbi(true) + .setVolumeUuid("foo3") + .setCodePath("foo4") + .addPermission(permission) + .addPermissionGroup(new ParsedPermissionGroup()) + .addActivity(new ParsedActivity()) + .addReceiver(new ParsedActivity()) + .addProvider(new ParsedProvider()) + .addService(new ParsedService()) + .addInstrumentation(new ParsedInstrumentation()) + .addRequestedPermission("foo7") + .addImplicitPermission("foo25") + .addProtectedBroadcast("foo8") + .setStaticSharedLibName("foo23") + .setStaticSharedLibVersion(100) + .addUsesStaticLibrary("foo23") + .addUsesStaticLibraryCertDigests(new String[]{"digest"}) + .addUsesStaticLibraryVersion(100) + .addLibraryName("foo10") + .addUsesLibrary("foo11") + .addUsesOptionalLibrary("foo12") + .addOriginalPackage("foo14") + .setRealPackage("foo15") + .addAdoptPermission("foo16") + .setAppMetaData(bundle) + .setVersionName("foo17") + .setSharedUserId("foo18") + .setSigningDetails( + new PackageParser.SigningDetails( + new Signature[]{new Signature(new byte[16])}, + 2, + new ArraySet<>(), + null) + ) + .setRestrictedAccountType("foo19") + .setRequiredAccountType("foo20") + .setOverlayTarget("foo21") + .setOverlayPriority(100) + .setUpgradeKeySets(new ArraySet<>()) + .addPreferredActivityFilter( + new ComponentParseUtils.ParsedActivityIntentInfo("foo", "className")) + .addConfigPreference(new ConfigurationInfo()) + .addReqFeature(new FeatureInfo()) + .addFeatureGroup(new FeatureGroupInfo()) + .setCompileSdkVersionCodename("foo23") + .setCompileSdkVersion(100) + .setOverlayCategory("foo24") + .setOverlayIsStatic(true) + .setOverlayTargetName("foo26") + .setVisibleToInstantApps(true) + .setSplitHasCode(0, true) + .hideAsParsed() + .setBaseCodePath("foo5") + .setVersionCode(100) + .setCpuAbiOverride("foo22") + .setRestrictUpdateHash(new byte[16]) + .setVersionCodeMajor(100) + .setCoreApp(true) + .hideAsFinal() + .mutate() + .setUsesLibraryInfos(Arrays.asList( + new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null) + )) + .setUsesLibraryFiles(new String[]{"foo13"}); } - private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception { - Field[] fields = PackageParser.Package.class.getDeclaredFields(); + private static void assertAllFieldsExist(ParsedPackage pkg) throws Exception { + Field[] fields = ParsedPackage.class.getDeclaredFields(); Set<String> nonSerializedFields = new HashSet<>(); nonSerializedFields.add("mExtras"); @@ -601,7 +612,7 @@ public class PackageParserTest { } else if (fieldType == boolean.class) { // boolean fields: Check that they're set to true. boolean value = (boolean) f.get(pkg); - assertEquals("Bad value for field: " + f, true, value); + assertTrue("Bad value for field: " + f, value); } else { // All other fields: Check that they're set. Object o = f.get(pkg); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java index 8d476f6e9318..2473997a61c9 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java @@ -16,14 +16,13 @@ package com.android.server.pm; -import android.content.pm.PackageParser; import android.content.pm.PackageUserState; +import android.content.pm.parsing.AndroidPackage; import android.util.SparseArray; import java.io.File; -import java.util.List; -class PackageSettingBuilder { +public class PackageSettingBuilder { private String mName; private String mRealName; private String mCodePath; @@ -35,17 +34,15 @@ class PackageSettingBuilder { private long mPVersionCode; private int mPkgFlags; private int mPrivateFlags; - private String mParentPackageName; - private List<String> mChildPackageNames; private int mSharedUserId; private String[] mUsesStaticLibraries; private long[] mUsesStaticLibrariesVersions; private String mVolumeUuid; private SparseArray<PackageUserState> mUserStates = new SparseArray<>(); - private PackageParser.Package mPkg; + private AndroidPackage mPkg; private int mAppId; - public PackageSettingBuilder setPackage(PackageParser.Package pkg) { + public PackageSettingBuilder setPackage(AndroidPackage pkg) { this.mPkg = pkg; return this; } @@ -111,16 +108,6 @@ class PackageSettingBuilder { return this; } - public PackageSettingBuilder setParentPackageName(String parentPackageName) { - this.mParentPackageName = parentPackageName; - return this; - } - - public PackageSettingBuilder setChildPackageNames(List<String> childPackageNames) { - this.mChildPackageNames = childPackageNames; - return this; - } - public PackageSettingBuilder setSharedUserId(int sharedUserId) { this.mSharedUserId = sharedUserId; return this; @@ -154,9 +141,8 @@ class PackageSettingBuilder { final PackageSetting packageSetting = new PackageSetting(mName, mRealName, new File(mCodePath), new File(mResourcePath), mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString, - mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mParentPackageName, - mChildPackageNames, mSharedUserId, mUsesStaticLibraries, - mUsesStaticLibrariesVersions); + mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mSharedUserId, + mUsesStaticLibraries, mUsesStaticLibrariesVersions); packageSetting.pkg = mPkg; packageSetting.appId = mAppId; packageSetting.volumeUuid = this.mVolumeUuid; 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 d3a77d3e80f1..04e769d7dcfb 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java @@ -16,8 +16,8 @@ package com.android.server.pm; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -467,8 +467,7 @@ public class PackageSignaturesTest { File appPath = new File("/data/app/app"); PackageSetting result = new PackageSetting("test.app", null, appPath, appPath, "/data/app/app", null, null, null, - 1, 940097092, 0, null, - null, 0 /*userId*/, null, null); + 1, 940097092, 0, 0 /*userId*/, null, null); return result; } } diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java index 41489dc42a6a..a0efc8a03719 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java @@ -17,6 +17,7 @@ package com.android.server.pm; import android.content.pm.PackageParser; +import android.content.pm.parsing.ParsedPackage; import android.util.Log; import androidx.test.runner.AndroidJUnit4; @@ -74,7 +75,7 @@ public class ParallelPackageParserTest { } @Override - protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile, + protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile, int parseFlags) throws PackageParser.PackageParserException { // Do not actually parse the package for testing return null; diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java index 4b7dd36a382a..30108c67d920 100644 --- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java @@ -18,14 +18,17 @@ package com.android.server.pm; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.os.Build; import android.platform.test.annotations.Presubmit; import com.android.server.compat.PlatformCompat; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -40,41 +43,45 @@ import org.mockito.junit.MockitoJUnitRunner; public class SELinuxMMACTest { private static final String PACKAGE_NAME = "my.package"; - private static final int OPT_IN_VERSION = android.os.Build.VERSION_CODES.R; + private static final int OPT_IN_VERSION = Build.VERSION_CODES.R; @Mock PlatformCompat mMockCompatibility; - PackageParser.Package mPkg; - - @Before - public void setUp() { - mPkg = new PackageParser.Package(PACKAGE_NAME); - mPkg.applicationInfo.targetSdkVersion = 28; - } - @Test public void getSeInfoOptInToLatest() { - when(mMockCompatibility.isChangeEnabled(SELinuxMMAC.SELINUX_LATEST_CHANGES, - mPkg.applicationInfo)).thenReturn(true); - assertThat(SELinuxMMAC.getSeInfo(mPkg, null, mMockCompatibility), + AndroidPackage pkg = makePackage(Build.VERSION_CODES.P); + when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES), + argThat(argument -> argument.packageName.equals(pkg.getPackageName())))) + .thenReturn(true); + assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility), is("default:targetSdkVersion=" + OPT_IN_VERSION)); } @Test public void getSeInfoNoOptIn() { - when(mMockCompatibility.isChangeEnabled(SELinuxMMAC.SELINUX_LATEST_CHANGES, - mPkg.applicationInfo)).thenReturn(false); - assertThat(SELinuxMMAC.getSeInfo(mPkg, null, mMockCompatibility), + AndroidPackage pkg = makePackage(Build.VERSION_CODES.P); + when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES), + argThat(argument -> argument.packageName.equals(pkg.getPackageName())))) + .thenReturn(false); + assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility), is("default:targetSdkVersion=28")); } @Test public void getSeInfoNoOptInButAlreadyR() { - mPkg.applicationInfo.targetSdkVersion = OPT_IN_VERSION; - when(mMockCompatibility.isChangeEnabled(SELinuxMMAC.SELINUX_LATEST_CHANGES, - mPkg.applicationInfo)).thenReturn(false); - assertThat(SELinuxMMAC.getSeInfo(mPkg, null, mMockCompatibility), + AndroidPackage pkg = makePackage(OPT_IN_VERSION); + when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES), + argThat(argument -> argument.packageName.equals(pkg.getPackageName())))) + .thenReturn(false); + assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility), is("default:targetSdkVersion=" + OPT_IN_VERSION)); } + + private AndroidPackage makePackage(int targetSdkVersion) { + return PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(targetSdkVersion) + .hideAsParsed() + .hideAsFinal(); + } } diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java index 34a3f860496a..11f154be688b 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java +++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java @@ -16,12 +16,13 @@ package com.android.server.pm; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsedPackage; import android.os.UserHandle; class ScanRequestBuilder { - private final PackageParser.Package mPkg; - private PackageParser.Package mOldPkg; + private final ParsedPackage mPkg; + private AndroidPackage mOldPkg; private SharedUserSetting mSharedUserSetting; private PackageSetting mPkgSetting; private PackageSetting mDisabledPkgSetting; @@ -32,11 +33,11 @@ class ScanRequestBuilder { private UserHandle mUser; private boolean mIsPlatformPackage; - ScanRequestBuilder(PackageParser.Package pkg) { + ScanRequestBuilder(ParsedPackage pkg) { this.mPkg = pkg; } - public ScanRequestBuilder setOldPkg(PackageParser.Package oldPkg) { + public ScanRequestBuilder setOldPkg(AndroidPackage oldPkg) { this.mOldPkg = oldPkg; return this; } 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 74ef034082a0..583cf5827367 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java @@ -35,13 +35,18 @@ import static org.junit.Assert.assertNotSame; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.Manifest; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; -import android.content.pm.PackageParser; import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.PackageInfoUtils; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.ParsingPackage; +import android.content.res.TypedArray; import android.os.Environment; import android.os.UserHandle; import android.os.UserManagerInternal; @@ -60,6 +65,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import java.io.File; +import java.util.UUID; @RunWith(MockitoJUnitRunner.class) @Presubmit @@ -68,6 +74,9 @@ public class ScanTests { private static final String DUMMY_PACKAGE_NAME = "some.app.to.test"; + private static final UUID UUID_ONE = UUID.randomUUID(); + private static final UUID UUID_TWO = UUID.randomUUID(); + @Mock PackageAbiHelper mMockPackageAbiHelper; @Mock @@ -92,25 +101,25 @@ public class ScanTests { @Before public void setupDefaultAbiBehavior() throws Exception { when(mMockPackageAbiHelper.derivePackageAbi( - any(PackageParser.Package.class), nullable(String.class), anyBoolean())) + any(ParsedPackage.class), nullable(String.class), anyBoolean())) .thenReturn(new Pair<>( new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"), new PackageAbiHelper.NativeLibraryPaths( "derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2"))); when(mMockPackageAbiHelper.getNativeLibraryPaths( - any(PackageParser.Package.class), any(File.class))) + any(ParsedPackage.class), any(File.class))) .thenReturn(new PackageAbiHelper.NativeLibraryPaths( "getRootDir", true, "getNativeDir", "getNativeDir2" )); when(mMockPackageAbiHelper.getBundledAppAbis( - any(PackageParser.Package.class))) + any(ParsedPackage.class))) .thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary")); } @Test public void newInstallSimpleAllNominal() throws Exception { final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL) .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP) .build(); @@ -128,7 +137,7 @@ public class ScanTests { when(mMockUserManager.getUserIds()).thenReturn(userIds); final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .setRealPkgName(null) .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL) .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP) @@ -143,7 +152,7 @@ public class ScanTests { @Test public void installRealPackageName() throws Exception { final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .setRealPkgName("com.package.real") .build(); @@ -154,7 +163,7 @@ public class ScanTests { final PackageManagerService.ScanRequest scanRequestNoRealPkg = createBasicScanRequestBuilder( createBasicPackage(DUMMY_PACKAGE_NAME) - .setRealPackageName("com.package.real").build()) + .setRealPackage("com.package.real")) .build(); final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg); @@ -170,7 +179,7 @@ public class ScanTests { .setSecondaryCpuAbiString("secondaryCpuAbi") .build(); final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP) .setPkgSetting(pkgSetting) .build(); @@ -202,7 +211,7 @@ public class ScanTests { .build(); final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .setPkgSetting(existingPkgSetting) .build(); @@ -214,17 +223,18 @@ public class ScanTests { @Test public void installStaticSharedLibrary() throws Exception { - final PackageParser.Package pkg = createBasicPackage("static.lib.pkg.123") - .setStaticSharedLib("static.lib", 123L) - .setManifestPackageName("static.lib.pkg") + final ParsedPackage pkg = createBasicPackage("static.lib.pkg") + .setStaticSharedLibName("static.lib") + .setStaticSharedLibVersion(123L) + .hideAsParsed() + .setPackageName("static.lib.pkg.123") .setVersionCodeMajor(1) .setVersionCode(234) .setBaseCodePath("/some/path.apk") - .addSplitCodePath("/some/other/path.apk") - .build(); + .setSplitCodePaths(new String[] {"/some/other/path.apk"}); - final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder( - pkg).setUser(UserHandle.of(0)).build(); + final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(pkg) + .setUser(UserHandle.of(0)).build(); final PackageManagerService.ScanResult scanResult = executeScan(scanRequest); @@ -245,15 +255,14 @@ public class ScanTests { @Test public void installDynamicLibraries() throws Exception { - final PackageParser.Package pkg = createBasicPackage("dynamic.lib.pkg") - .setManifestPackageName("dynamic.lib.pkg") + final ParsedPackage pkg = createBasicPackage("dynamic.lib.pkg") .addLibraryName("liba") .addLibraryName("libb") + .hideAsParsed() .setVersionCodeMajor(1) .setVersionCode(234) .setBaseCodePath("/some/path.apk") - .addSplitCodePath("/some/other/path.apk") - .build(); + .setSplitCodePaths(new String[] {"/some/other/path.apk"}); final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build(); @@ -295,15 +304,15 @@ public class ScanTests { .setVolumeUuid("someUuid") .build(); - final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) - .setApplicationInfoVolumeUuid("someNewUuid") - .build(); + final ParsedPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) + .hideAsParsed() + .setApplicationVolumeUuid(UUID_TWO.toString()); final PackageManagerService.ScanResult scanResult = executeScan( new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build()); - assertThat(scanResult.pkgSetting.volumeUuid, is("someNewUuid")); + assertThat(scanResult.pkgSetting.volumeUuid, is(UUID_TWO.toString())); } @Test @@ -311,10 +320,10 @@ public class ScanTests { final PackageSetting pkgSetting = createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build(); - final PackageParser.Package basicPackage = + final ParsedPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) - .setCpuAbiOVerride("testOverride") - .build(); + .hideAsParsed() + .setCpuAbiOverride("testOverride"); final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder( @@ -331,9 +340,9 @@ public class ScanTests { final PackageSetting originalPkgSetting = createBasicPackageSettingBuilder("original.package").build(); - final PackageParser.Package basicPackage = + final ParsedPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) - .build(); + .hideAsParsed(); final PackageManagerService.ScanResult result = @@ -341,7 +350,7 @@ public class ScanTests { .setOriginalPkgSetting(originalPkgSetting) .build()); - assertThat(result.request.pkg.packageName, is("original.package")); + assertThat(result.request.parsedPackage.getPackageName(), is("original.package")); } @Test @@ -354,7 +363,7 @@ public class ScanTests { .build(); final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .setPkgSetting(existingPkgSetting) .addScanFlag(SCAN_AS_FULL_APP) .build(); @@ -375,7 +384,7 @@ public class ScanTests { .build(); final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .setPkgSetting(existingPkgSetting) .addScanFlag(SCAN_AS_INSTANT_APP) .build(); @@ -394,7 +403,7 @@ public class ScanTests { .build(); final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .setPkgSetting(existingPkgSetting) .setDisabledPkgSetting(existingPkgSetting) .addScanFlag(SCAN_NEW_INSTALL) @@ -402,15 +411,14 @@ public class ScanTests { final PackageManagerService.ScanResult scanResult = executeScan(scanRequest); - assertThat(scanResult.request.pkg.applicationInfo.flags, + assertThat(scanResult.request.parsedPackage.getFlags(), hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)); } @Test public void factoryTestFlagSet() throws Exception { - final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) - .addPermissionRequest(Manifest.permission.FACTORY_TEST) - .build(); + final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) + .addRequestedPermission(Manifest.permission.FACTORY_TEST); final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI( createBasicScanRequestBuilder(basicPackage).build(), @@ -418,15 +426,15 @@ public class ScanTests { true /*isUnderFactoryTest*/, System.currentTimeMillis()); - assertThat(scanResult.request.pkg.applicationInfo.flags, + assertThat(scanResult.request.parsedPackage.getFlags(), hasFlag(ApplicationInfo.FLAG_FACTORY_TEST)); } @Test public void scanSystemApp_isOrphanedTrue() throws Exception { - final PackageParser.Package pkg = createBasicPackage(DUMMY_PACKAGE_NAME) - .addApplicationInfoFlag(ApplicationInfo.FLAG_SYSTEM) - .build(); + final ParsedPackage pkg = createBasicPackage(DUMMY_PACKAGE_NAME) + .hideAsParsed() + .setSystem(true); final PackageManagerService.ScanRequest scanRequest = createBasicScanRequestBuilder(pkg) @@ -481,22 +489,29 @@ public class ScanTests { .setResourcePath(createResourcePath(packageName)); } - private static ScanRequestBuilder createBasicScanRequestBuilder(PackageParser.Package pkg) { - return new ScanRequestBuilder(pkg) + private static ScanRequestBuilder createBasicScanRequestBuilder(ParsingPackage pkg) { + return new ScanRequestBuilder(pkg.hideAsParsed()) .setUser(UserHandle.of(0)); } + private static ScanRequestBuilder createBasicScanRequestBuilder(ParsedPackage pkg) { + return new ScanRequestBuilder(pkg) + .setUser(UserHandle.of(0)); + } - private static PackageBuilder createBasicPackage(String packageName) { - return new PackageBuilder(packageName) + private static ParsingPackage createBasicPackage(String packageName) { + // TODO(b/135203078): Make this use PackageImpl.forParsing and separate the steps + return new PackageImpl(packageName, null, mock(TypedArray.class), false) .setCodePath("/data/tmp/randompath") .setApplicationInfoCodePath(createCodePath(packageName)) .setApplicationInfoResourcePath(createResourcePath(packageName)) - .setApplicationInfoVolumeUuid("volumeUuid") + .setApplicationVolumeUuid(UUID_ONE.toString()) .setBaseCodePath("/data/tmp/randompath/base.apk") - .addUsesStaticLibrary("some.static.library", 234L) - .addUsesStaticLibrary("some.other.static.library", 456L) - .setApplicationInfoNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib") + .addUsesStaticLibrary("some.static.library") + .addUsesStaticLibraryVersion(234L) + .addUsesStaticLibrary("some.other.static.library") + .addUsesStaticLibraryVersion(456L) + .setNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib") .setVersionCodeMajor(1) .setVersionCode(2345); } @@ -508,20 +523,19 @@ public class ScanTests { final PackageSetting pkgSetting = scanResult.pkgSetting; assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting); - final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo; + final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo( + pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0); assertBasicApplicationInfo(scanResult, applicationInfo); - } private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult, String packageName, boolean isInstant, PackageSetting pkgSetting) { - assertThat(pkgSetting.pkg.packageName, is(packageName)); + assertThat(pkgSetting.pkg.getPackageName(), is(packageName)); assertThat(pkgSetting.getInstantApp(0), is(isInstant)); assertThat(pkgSetting.usesStaticLibraries, arrayContaining("some.static.library", "some.other.static.library")); assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L})); - assertThat(pkgSetting.pkg, is(scanResult.request.pkg)); - assertThat(pkgSetting.pkg.mExtras, is(pkgSetting)); + assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage)); assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName)))); assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName)))); assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345))); @@ -529,34 +543,39 @@ public class ScanTests { private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult, ApplicationInfo applicationInfo) { - assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName)); + assertThat(applicationInfo.processName, + is(scanResult.request.parsedPackage.getPackageName())); final int uid = applicationInfo.uid; assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM)); final String calculatedCredentialId = Environment.getDataUserCePackageDirectory( applicationInfo.volumeUuid, UserHandle.USER_SYSTEM, - scanResult.request.pkg.packageName).getAbsolutePath(); + scanResult.request.parsedPackage.getPackageName()).getAbsolutePath(); assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId)); assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir)); } private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) { - final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo; + PackageSetting pkgSetting = scanResult.pkgSetting; + final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo( + pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0); assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary")); assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary")); assertThat(applicationInfo.nativeLibraryRootDir, is("derivedRootDir")); - assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("derivedRootDir")); + assertThat(pkgSetting.legacyNativeLibraryPathString, is("derivedRootDir")); assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true)); assertThat(applicationInfo.nativeLibraryDir, is("derivedNativeDir")); assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2")); } private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) { - final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo; + PackageSetting pkgSetting = scanResult.pkgSetting; + final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo( + pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0); assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir")); - assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("getRootDir")); + assertThat(pkgSetting.legacyNativeLibraryPathString, is("getRootDir")); assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true)); assertThat(applicationInfo.nativeLibraryDir, is("getNativeDir")); assertThat(applicationInfo.secondaryNativeLibraryDir, is("getNativeDir2")); diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java index 790f2b47cdd5..683278b699c0 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java @@ -37,8 +37,9 @@ import static org.junit.Assert.fail; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; import android.content.pm.UserInfo; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; import android.os.Looper; import android.os.SystemProperties; import android.os.UserManager; @@ -250,10 +251,14 @@ public class UserSystemPackageInstallerTest { final Set<String> userWhitelist = new ArraySet<>(); userWhitelist.add(packageName1); - final PackageParser.Package pkg1 = new PackageParser.Package(packageName1); - final PackageParser.Package pkg2 = new PackageParser.Package(packageName2); - final PackageParser.Package pkg3 = new PackageParser.Package(packageName3); - final PackageParser.Package pkg4 = new PackageParser.Package(packageName4); + final AndroidPackage pkg1 = PackageImpl.forParsing(packageName1) + .hideAsParsed().hideAsFinal(); + final AndroidPackage pkg2 = PackageImpl.forParsing(packageName2) + .hideAsParsed().hideAsFinal(); + final AndroidPackage pkg3 = PackageImpl.forParsing(packageName3) + .hideAsParsed().hideAsFinal(); + final AndroidPackage pkg4 = PackageImpl.forParsing(packageName4) + .hideAsParsed().hideAsFinal(); // No implicit whitelist, so only install pkg1. boolean implicit = false; diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java index 3a55c2290157..66a4946ecc20 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java @@ -22,8 +22,11 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import android.content.pm.ApplicationInfo; import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.ParsingPackage; import android.util.SparseArray; import androidx.test.filters.SmallTest; @@ -51,17 +54,18 @@ public class DexoptUtilsTest { DelegateLastClassLoader.class.getName(); private static class TestData { - ApplicationInfo info; + AndroidPackage pkg; boolean[] pathsWithCode; } private TestData createMockApplicationInfo(String baseClassLoader, boolean addSplits, - boolean addSplitDependencies) { - ApplicationInfo ai = new ApplicationInfo(); + boolean addSplitDependencies, boolean isolatedSplitLoading) { String codeDir = "/data/app/mock.android.com"; - ai.setBaseCodePath(codeDir + "/base.dex"); - ai.classLoaderName = baseClassLoader; - ai.privateFlags = ai.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING; + ParsingPackage parsingPackage = PackageImpl.forParsing("mock.android.com") + .setClassLoaderName(baseClassLoader); + + parsingPackage.setIsolatedSplitLoading(isolatedSplitLoading); + boolean[] pathsWithCode; if (!addSplits) { pathsWithCode = new boolean[] {true}; @@ -70,7 +74,7 @@ public class DexoptUtilsTest { Arrays.fill(pathsWithCode, true); pathsWithCode[7] = false; // config split - ai.setSplitCodePaths(new String[]{ + String[] splitCodePaths = new String[]{ codeDir + "/base-1.dex", codeDir + "/base-2.dex", codeDir + "/base-3.dex", @@ -78,32 +82,51 @@ public class DexoptUtilsTest { codeDir + "/base-5.dex", codeDir + "/base-6.dex", codeDir + "/config-split-7.dex", - codeDir + "/feature-no-deps.dex"}); - - ai.splitClassLoaderNames = new String[]{ - DELEGATE_LAST_CLASS_LOADER_NAME, - DELEGATE_LAST_CLASS_LOADER_NAME, - PATH_CLASS_LOADER_NAME, - DEX_CLASS_LOADER_NAME, - PATH_CLASS_LOADER_NAME, - null, // A null class loader name should default to PathClassLoader. - null, // The config split gets a null class loader. - null}; // The feature split with no dependency and no specified class loader. + codeDir + "/feature-no-deps.dex" + }; + + String[] splitNames = new String[splitCodePaths.length]; + int[] splitRevisionCodes = new int[splitCodePaths.length]; + SparseArray<int[]> splitDependencies = null; + if (addSplitDependencies) { - ai.splitDependencies = new SparseArray<>(ai.splitClassLoaderNames.length + 1); - ai.splitDependencies.put(0, new int[] {-1}); // base has no dependency - ai.splitDependencies.put(1, new int[] {2}); // split 1 depends on 2 - ai.splitDependencies.put(2, new int[] {4}); // split 2 depends on 4 - ai.splitDependencies.put(3, new int[] {4}); // split 3 depends on 4 - ai.splitDependencies.put(4, new int[] {0}); // split 4 depends on base - ai.splitDependencies.put(5, new int[] {0}); // split 5 depends on base - ai.splitDependencies.put(6, new int[] {5}); // split 6 depends on 5 + splitDependencies = new SparseArray<>(splitCodePaths.length); + splitDependencies.put(0, new int[] {-1}); // base has no dependency + splitDependencies.put(1, new int[] {2}); // split 1 depends on 2 + splitDependencies.put(2, new int[] {4}); // split 2 depends on 4 + splitDependencies.put(3, new int[] {4}); // split 3 depends on 4 + splitDependencies.put(4, new int[] {0}); // split 4 depends on base + splitDependencies.put(5, new int[] {0}); // split 5 depends on base + splitDependencies.put(6, new int[] {5}); // split 6 depends on 5 // Do not add the config split to the dependency list. // Do not add the feature split with no dependency to the dependency list. } + + parsingPackage + .asSplit( + splitNames, + splitCodePaths, + splitRevisionCodes, + splitDependencies + ) + .setSplitClassLoaderName(0, DELEGATE_LAST_CLASS_LOADER_NAME) + .setSplitClassLoaderName(1, DELEGATE_LAST_CLASS_LOADER_NAME) + .setSplitClassLoaderName(2, PATH_CLASS_LOADER_NAME) + .setSplitClassLoaderName(3, DEX_CLASS_LOADER_NAME) + .setSplitClassLoaderName(4, PATH_CLASS_LOADER_NAME) + // A null class loader name should default to PathClassLoader + .setSplitClassLoaderName(5, null) + // The config split gets a null class loader + .setSplitClassLoaderName(6, null) + // The feature split with no dependency and no specified class loader. + .setSplitClassLoaderName(7, null); } + + ParsedPackage parsedPackage = parsingPackage.hideAsParsed() + .setBaseCodePath(codeDir + "/base.dex"); + TestData data = new TestData(); - data.info = ai; + data.pkg = parsedPackage.hideAsFinal(); data.pathsWithCode = pathsWithCode; return data; } @@ -118,11 +141,11 @@ public class DexoptUtilsTest { @Test public void testSplitChain() { - TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true); + TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true, true); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]); @@ -139,11 +162,11 @@ public class DexoptUtilsTest { @Test public void testSplitChainNoSplitDependencies() { - TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false); + TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false, true); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]); @@ -167,11 +190,9 @@ public class DexoptUtilsTest { @Test public void testSplitChainNoIsolationNoSharedLibrary() { - TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true); - data.info.privateFlags = data.info.privateFlags - & (~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING); + TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true, false); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, null, data.pathsWithCode); + data.pkg, null, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals("PCL[]", contexts[0]); @@ -192,9 +213,9 @@ public class DexoptUtilsTest { @Test public void testSplitChainNoSharedLibraries() { TestData data = createMockApplicationInfo( - DELEGATE_LAST_CLASS_LOADER_NAME, true, true); + DELEGATE_LAST_CLASS_LOADER_NAME, true, true, true); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, null, data.pathsWithCode); + data.pkg, null, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals("DLC[]", contexts[0]); @@ -211,11 +232,11 @@ public class DexoptUtilsTest { @Test public void testSplitChainWithNullPrimaryClassLoader() { // A null classLoaderName should mean PathClassLoader. - TestData data = createMockApplicationInfo(null, true, true); + TestData data = createMockApplicationInfo(null, true, true, true); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]); @@ -233,11 +254,11 @@ public class DexoptUtilsTest { @Test public void tesNoSplits() { - TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false); + TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false, true); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(1, contexts.length); assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]); @@ -245,11 +266,11 @@ public class DexoptUtilsTest { @Test public void tesNoSplitsNullClassLoaderName() { - TestData data = createMockApplicationInfo(null, false, false); + TestData data = createMockApplicationInfo(null, false, false, true); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(1, contexts.length); assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]); @@ -258,11 +279,11 @@ public class DexoptUtilsTest { @Test public void tesNoSplitDelegateLast() { TestData data = createMockApplicationInfo( - DELEGATE_LAST_CLASS_LOADER_NAME, false, false); + DELEGATE_LAST_CLASS_LOADER_NAME, false, false, true); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(1, contexts.length); assertEquals("DLC[]{PCL[a.dex:b.dex]}", contexts[0]); @@ -270,9 +291,9 @@ public class DexoptUtilsTest { @Test public void tesNoSplitsNoSharedLibraries() { - TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false); + TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false, true); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, null, data.pathsWithCode); + data.pkg, null, data.pathsWithCode); assertEquals(1, contexts.length); assertEquals("PCL[]", contexts[0]); @@ -281,9 +302,9 @@ public class DexoptUtilsTest { @Test public void tesNoSplitDelegateLastNoSharedLibraries() { TestData data = createMockApplicationInfo( - DELEGATE_LAST_CLASS_LOADER_NAME, false, false); + DELEGATE_LAST_CLASS_LOADER_NAME, false, false, true); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, null, data.pathsWithCode); + data.pkg, null, data.pathsWithCode); assertEquals(1, contexts.length); assertEquals("DLC[]", contexts[0]); @@ -291,13 +312,13 @@ public class DexoptUtilsTest { @Test public void testContextWithNoCode() { - TestData data = createMockApplicationInfo(null, true, false); + TestData data = createMockApplicationInfo(null, true, false, true); Arrays.fill(data.pathsWithCode, false); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals(null, contexts[0]); @@ -312,12 +333,12 @@ public class DexoptUtilsTest { @Test public void testContextBaseNoCode() { - TestData data = createMockApplicationInfo(null, true, true); + TestData data = createMockApplicationInfo(null, true, true, true); data.pathsWithCode[0] = false; List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals(null, contexts[0]); diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt new file mode 100644 index 000000000000..27d02e194540 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing + +import android.content.pm.ApplicationInfo +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.content.pm.PackageParser +import android.content.pm.parsing.AndroidPackage +import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.appInfo +import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.pkgInfo +import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.assertWithMessage +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized + +/** + * Verifies that missing/adding [PackageManager] flags adds/remove the appropriate fields from the + * [PackageInfo] or [ApplicationInfo] results. + * + * This test has to be updated manually whenever the info generation behavior changes, since + * there's no single place where flag -> field is defined besides this test. + */ +@RunWith(Parameterized::class) +class AndroidPackageInfoFlagBehaviorTest : AndroidPackageParsingTestBase() { + + companion object { + + data class Param<T> constructor( + val flag: Int, + val logTag: String, + val oldPkgFunction: (pkg: PackageParser.Package, flags: Int) -> T?, + val newPkgFunction: (pkg: AndroidPackage, flags: Int) -> T?, + val fieldFunction: (T) -> List<Any?> + ) { + companion object { + fun pkgInfo(flag: Int, fieldFunction: (PackageInfo) -> List<Any?>) = Param( + flag, PackageInfo::class.java.simpleName, + ::oldPackageInfo, ::newPackageInfo, fieldFunction + ) + + fun appInfo(flag: Int, fieldFunction: (ApplicationInfo) -> List<Any?>) = Param( + flag, ApplicationInfo::class.java.simpleName, + ::oldAppInfo, ::newAppInfo, fieldFunction + ) + } + + override fun toString(): String { + val hex = Integer.toHexString(flag) + val fromRight = Integer.toBinaryString(flag).reversed().indexOf('1') + return "$logTag $hex | 1 shl $fromRight" + } + } + + @JvmStatic + @Parameterized.Parameters(name = "{0}") + fun parameters() = arrayOf( + pkgInfo(PackageManager.GET_ACTIVITIES) { listOf(it.activities) }, + pkgInfo(PackageManager.GET_GIDS) { listOf(it.gids) }, + pkgInfo(PackageManager.GET_INSTRUMENTATION) { listOf(it.instrumentation) }, + pkgInfo(PackageManager.GET_META_DATA) { listOf(it.applicationInfo.metaData) }, + pkgInfo(PackageManager.GET_PROVIDERS) { listOf(it.providers) }, + pkgInfo(PackageManager.GET_RECEIVERS) { listOf(it.receivers) }, + pkgInfo(PackageManager.GET_SERVICES) { listOf(it.services) }, + pkgInfo(PackageManager.GET_SIGNATURES) { listOf(it.signatures) }, + pkgInfo(PackageManager.GET_SIGNING_CERTIFICATES) { listOf(it.signingInfo) }, + pkgInfo(PackageManager.GET_SHARED_LIBRARY_FILES) { + it.applicationInfo.run { listOf(sharedLibraryFiles, sharedLibraryFiles) } + }, + pkgInfo(PackageManager.GET_CONFIGURATIONS) { + listOf(it.configPreferences, it.reqFeatures, it.featureGroups) + }, + pkgInfo(PackageManager.GET_PERMISSIONS) { + listOf(it.permissions, it.requestedPermissions, it.requestedPermissionsFlags) + }, + + appInfo(PackageManager.GET_META_DATA) { listOf(it.metaData) }, + appInfo(PackageManager.GET_SHARED_LIBRARY_FILES) { + listOf(it.sharedLibraryFiles, it.sharedLibraryFiles) + } + ) + } + + @Parameterized.Parameter(0) + lateinit var param: Param<Any> + + @Test + fun fieldPresence() { + oldPackages.asSequence().zip(newPackages.asSequence()) + .forEach { (old, new) -> + val oldWithFlag = param.oldPkgFunction(old, param.flag) + val newWithFlag = param.newPkgFunction(new, param.flag) + val oldFieldList = oldWithFlag?.let(param.fieldFunction).orEmpty() + val newFieldList = newWithFlag?.let(param.fieldFunction).orEmpty() + + oldFieldList.zip(newFieldList).forEach { + assertWithMessage(new.packageName).that(it.second).apply { + // Assert same null-ness as old logic + if (it.first == null) { + isNull() + } else { + isNotNull() + } + } + } + } + } + + @Test + fun fieldAbsence() { + newPackages.forEach { + val newWithoutFlag = param.newPkgFunction(it, 0) + val newFieldListWithoutFlag = newWithoutFlag?.let(param.fieldFunction).orEmpty() + assertThat(newFieldListWithoutFlag.filterNotNull()).isEmpty() + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt new file mode 100644 index 000000000000..925af7fba82a --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing + +import android.content.pm.PackageManager +import com.google.common.truth.Truth.assertWithMessage +import org.junit.Test + +/** + * Collects APKs from the device and verifies that the new parsing behavior outputs + * the same exposed Info object as the old parsing logic. + */ +class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() { + + @Test + fun applicationInfoEquality() { + val flags = PackageManager.GET_META_DATA or PackageManager.GET_SHARED_LIBRARY_FILES + val oldAppInfo = oldPackages.asSequence().map { oldAppInfo(it, flags) } + val newAppInfo = newPackages.asSequence().map { newAppInfo(it, flags) } + oldAppInfo.zip(newAppInfo).forEach { + val firstName = it.first?.packageName + val secondName = it.second?.packageName + val packageName = if (firstName == secondName) { + "$firstName" + } else { + "$firstName | $secondName" + } + assertWithMessage(packageName).that(it.first?.dumpToString()) + .isEqualTo(it.second?.dumpToString()) + } + } + + @Test + fun packageInfoEquality() { + val flags = PackageManager.GET_ACTIVITIES or + PackageManager.GET_CONFIGURATIONS or + PackageManager.GET_GIDS or + PackageManager.GET_INSTRUMENTATION or + PackageManager.GET_META_DATA or + PackageManager.GET_PERMISSIONS or + PackageManager.GET_PROVIDERS or + PackageManager.GET_RECEIVERS or + PackageManager.GET_SERVICES or + PackageManager.GET_SHARED_LIBRARY_FILES or + PackageManager.GET_SIGNATURES or + PackageManager.GET_SIGNING_CERTIFICATES + val oldPackageInfo = oldPackages.asSequence().map { oldPackageInfo(it, flags) } + val newPackageInfo = newPackages.asSequence().map { newPackageInfo(it, flags) } + + oldPackageInfo.zip(newPackageInfo).forEach { + val firstName = it.first?.packageName + val secondName = it.second?.packageName + val packageName = if (firstName == secondName) { + "$firstName" + } else { + "$firstName | $secondName" + } + assertWithMessage(packageName).that(it.first?.dumpToString()) + .isEqualTo(it.second?.dumpToString()) + } + } +} + + diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt new file mode 100644 index 000000000000..afd6e1851cde --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing + +import android.content.Context +import android.content.pm.ActivityInfo +import android.content.pm.ApplicationInfo +import android.content.pm.ConfigurationInfo +import android.content.pm.FeatureInfo +import android.content.pm.InstrumentationInfo +import android.content.pm.PackageInfo +import android.content.pm.PackageParser +import android.content.pm.PackageUserState +import android.content.pm.PermissionInfo +import android.content.pm.ProviderInfo +import android.content.pm.parsing.AndroidPackage +import android.content.pm.parsing.PackageImpl +import android.content.pm.parsing.PackageInfoUtils +import android.os.Debug +import android.os.Environment +import android.util.SparseArray +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.pm.PackageManagerService +import org.junit.BeforeClass +import org.mockito.Mockito +import java.io.File + +open class AndroidPackageParsingTestBase { + + companion object { + + /** + * By default, don't parse all APKs on device, only the framework one. + * Toggle this manually if working on package parsing. + */ + private const val VERIFY_ALL_APKS = false + + /** For auditing memory usage differences */ + private const val DUMP_HPROF_TO_EXTERNAL = false + + val context: Context = InstrumentationRegistry.getInstrumentation().getContext() + protected val packageParser = PackageParser().apply { + setOnlyCoreApps(false) + setDisplayMetrics(context.resources.displayMetrics) + setCallback { true } + } + + /** + * It would be difficult to mock all possibilities, so just use the APKs on device. + * Unfortunately, this means the device must be bootable to verify potentially + * boot-breaking behavior. + */ + private val apks = mutableListOf(File(Environment.getRootDirectory(), "framework")) + .apply { + @Suppress("ConstantConditionIf") + if (VERIFY_ALL_APKS) { + this += (PackageManagerService.SYSTEM_PARTITIONS) + .flatMap { + listOfNotNull(it.privAppFolder, it.appFolder, it.overlayFolder) + } + } + } + .flatMap { + it.walkTopDown() + .filter { file -> file.name.endsWith(".apk") } + .toList() + } + + private val dummyState = Mockito.mock(PackageUserState::class.java).apply { + installed = true + Mockito.`when`(isAvailable(Mockito.anyInt())).thenReturn(true) + } + + lateinit var oldPackages: List<PackageParser.Package> + + lateinit var newPackages: List<AndroidPackage> + + @Suppress("ConstantConditionIf") + @JvmStatic + @BeforeClass + fun setUpPackages() { + this.oldPackages = apks.map { + packageParser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false) + } + + this.newPackages = apks.map { + packageParser.parseParsedPackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false) + } + + if (DUMP_HPROF_TO_EXTERNAL) { + System.gc() + Environment.getExternalStorageDirectory() + .resolve("${AndroidPackageParsingTestBase::class.java.simpleName}.hprof") + .absolutePath + .run(Debug::dumpHprofData) + } + } + + fun oldAppInfo(pkg: PackageParser.Package, flags: Int = 0): ApplicationInfo? { + return PackageParser.generateApplicationInfo(pkg, flags, dummyState, 0) + } + + fun newAppInfo(pkg: AndroidPackage, flags: Int = 0): ApplicationInfo? { + return PackageInfoUtils.generateApplicationInfo(pkg, flags, dummyState, 0) + } + + fun oldPackageInfo(pkg: PackageParser.Package, flags: Int = 0): PackageInfo? { + return PackageParser.generatePackageInfo(pkg, intArrayOf(), flags, 5, 6, emptySet(), dummyState) + } + + fun newPackageInfo(pkg: AndroidPackage, flags: Int = 0): PackageInfo? { + return PackageInfoUtils.generate(pkg, intArrayOf(), flags, 5, 6, emptySet(), dummyState, 0) + } + } + + // The following methods dump an exact set of fields from the object to compare, because + // 1. comprehensive equals/toStrings do not exist on all of the Info objects, and + // 2. the test must only verify fields that [PackageParser.Package] can actually fill, as + // no new functionality will be added to it. + + // The following methods prepend "this." because @hide APIs can cause an IDE to auto-import + // the R.attr constant instead of referencing the field in an attempt to fix the error. + + /** + * Known exclusions: + * - [ApplicationInfo.credentialProtectedDataDir] + * - [ApplicationInfo.dataDir] + * - [ApplicationInfo.deviceProtectedDataDir] + * - [ApplicationInfo.processName] + * - [ApplicationInfo.publicSourceDir] + * - [ApplicationInfo.scanPublicSourceDir] + * - [ApplicationInfo.scanSourceDir] + * - [ApplicationInfo.sourceDir] + * These attributes used to be assigned post-package-parsing as part of another component, + * but are now adjusted directly inside [PackageImpl]. + */ + protected fun ApplicationInfo.dumpToString() = """ + appComponentFactory=${this.appComponentFactory} + backupAgentName=${this.backupAgentName} + banner=${this.banner} + category=${this.category} + classLoaderName=${this.classLoaderName} + className=${this.className} + compatibleWidthLimitDp=${this.compatibleWidthLimitDp} + compileSdkVersion=${this.compileSdkVersion} + compileSdkVersionCodename=${this.compileSdkVersionCodename} + descriptionRes=${this.descriptionRes} + enabled=${this.enabled} + enabledSetting=${this.enabledSetting} + flags=${Integer.toBinaryString(this.flags)} + fullBackupContent=${this.fullBackupContent} + hiddenUntilInstalled=${this.hiddenUntilInstalled} + icon=${this.icon} + iconRes=${this.iconRes} + installLocation=${this.installLocation} + largestWidthLimitDp=${this.largestWidthLimitDp} + logo=${this.logo} + longVersionCode=${this.longVersionCode} + manageSpaceActivityName=${this.manageSpaceActivityName} + maxAspectRatio.compareTo(that.maxAspectRatio)=${this.maxAspectRatio} + metaData=${this.metaData} + minAspectRatio.compareTo(that.minAspectRatio)=${this.minAspectRatio} + minSdkVersion=${this.minSdkVersion} + name=${this.name} + nativeLibraryDir=${this.nativeLibraryDir} + nativeLibraryRootDir=${this.nativeLibraryRootDir} + nativeLibraryRootRequiresIsa=${this.nativeLibraryRootRequiresIsa} + networkSecurityConfigRes=${this.networkSecurityConfigRes} + nonLocalizedLabel=${this.nonLocalizedLabel} + packageName=${this.packageName} + permission=${this.permission} + primaryCpuAbi=${this.primaryCpuAbi} + privateFlags=${Integer.toBinaryString(this.privateFlags)} + requiresSmallestWidthDp=${this.requiresSmallestWidthDp} + resourceDirs=${this.resourceDirs?.contentToString()} + roundIconRes=${this.roundIconRes} + secondaryCpuAbi=${this.secondaryCpuAbi} + secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir} + seInfo=${this.seInfo} + seInfoUser=${this.seInfoUser} + sharedLibraryFiles=${this.sharedLibraryFiles?.contentToString()} + sharedLibraryInfos=${this.sharedLibraryInfos} + showUserIcon=${this.showUserIcon} + splitClassLoaderNames=${this.splitClassLoaderNames?.contentToString()} + splitDependencies=${this.splitDependencies} + splitNames=${this.splitNames?.contentToString()} + splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()} + splitSourceDirs=${this.splitSourceDirs?.contentToString()} + storageUuid=${this.storageUuid} + targetSandboxVersion=${this.targetSandboxVersion} + targetSdkVersion=${this.targetSdkVersion} + taskAffinity=${this.taskAffinity} + theme=${this.theme} + uid=${this.uid} + uiOptions=${this.uiOptions} + versionCode=${this.versionCode} + volumeUuid=${this.volumeUuid} + zygotePreloadName=${this.zygotePreloadName} + """.trimIndent() + + protected fun FeatureInfo.dumpToString() = """ + flags=${Integer.toBinaryString(this.flags)} + name=${this.name} + reqGlEsVersion=${this.reqGlEsVersion} + version=${this.version} + """.trimIndent() + + protected fun InstrumentationInfo.dumpToString() = """ + credentialProtectedDataDir=${this.credentialProtectedDataDir} + dataDir=${this.dataDir} + deviceProtectedDataDir=${this.deviceProtectedDataDir} + functionalTest=${this.functionalTest} + handleProfiling=${this.handleProfiling} + nativeLibraryDir=${this.nativeLibraryDir} + primaryCpuAbi=${this.primaryCpuAbi} + publicSourceDir=${this.publicSourceDir} + secondaryCpuAbi=${this.secondaryCpuAbi} + secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir} + sourceDir=${this.sourceDir} + splitDependencies=${this.splitDependencies.sequence().map { it.first to it.second?.contentToString() }.joinToString()} + splitNames=${this.splitNames?.contentToString()} + splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()} + splitSourceDirs=${this.splitSourceDirs?.contentToString()} + targetPackage=${this.targetPackage} + targetProcesses=${this.targetProcesses} + """.trimIndent() + + protected fun ActivityInfo.dumpToString() = """ + colorMode=${this.colorMode} + configChanges=${this.configChanges} + documentLaunchMode=${this.documentLaunchMode} + flags=${Integer.toBinaryString(this.flags)} + launchMode=${this.launchMode} + launchToken=${this.launchToken} + lockTaskLaunchMode=${this.lockTaskLaunchMode} + maxAspectRatio=${this.maxAspectRatio} + maxRecents=${this.maxRecents} + minAspectRatio=${this.minAspectRatio} + parentActivityName=${this.parentActivityName} + permission=${this.permission} + persistableMode=${this.persistableMode} + privateFlags=${Integer.toBinaryString(this.privateFlags)} + requestedVrComponent=${this.requestedVrComponent} + resizeMode=${this.resizeMode} + rotationAnimation=${this.rotationAnimation} + screenOrientation=${this.screenOrientation} + softInputMode=${this.softInputMode} + targetActivity=${this.targetActivity} + taskAffinity=${this.taskAffinity} + theme=${this.theme} + uiOptions=${this.uiOptions} + windowLayout=${this.windowLayout?.dumpToString()} + """.trimIndent() + + protected fun ActivityInfo.WindowLayout.dumpToString() = """ + gravity=${this.gravity} + height=${this.height} + heightFraction=${this.heightFraction} + minHeight=${this.minHeight} + minWidth=${this.minWidth} + width=${this.width} + widthFraction=${this.widthFraction} + """.trimIndent() + + protected fun PermissionInfo.dumpToString() = """ + backgroundPermission=${this.backgroundPermission} + descriptionRes=${this.descriptionRes} + flags=${Integer.toBinaryString(this.flags)} + group=${this.group} + nonLocalizedDescription=${this.nonLocalizedDescription} + protectionLevel=${this.protectionLevel} + requestRes=${this.requestRes} + """.trimIndent() + + protected fun ProviderInfo.dumpToString() = """ + authority=${this.authority} + flags=${Integer.toBinaryString(this.flags)} + forceUriPermissions=${this.forceUriPermissions} + grantUriPermissions=${this.grantUriPermissions} + initOrder=${this.initOrder} + isSyncable=${this.isSyncable} + multiprocess=${this.multiprocess} + pathPermissions=${this.pathPermissions?.joinToString { "readPermission=${it.readPermission}\nwritePermission=${it.writePermission}" }} + readPermission=${this.readPermission} + uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()} + writePermission=${this.writePermission} + """.trimIndent() + + protected fun ConfigurationInfo.dumpToString() = """ + reqGlEsVersion=${this.reqGlEsVersion} + reqInputFeatures=${this.reqInputFeatures} + reqKeyboardType=${this.reqKeyboardType} + reqNavigation=${this.reqNavigation} + reqTouchScreen=${this.reqTouchScreen} + """.trimIndent() + + protected fun PackageInfo.dumpToString() = """ + activities=${this.activities?.joinToString { it.dumpToString() }} + applicationInfo=${this.applicationInfo.dumpToString()} + baseRevisionCode=${this.baseRevisionCode} + compileSdkVersion=${this.compileSdkVersion} + compileSdkVersionCodename=${this.compileSdkVersionCodename} + configPreferences=${this.configPreferences?.joinToString { it.dumpToString() }} + coreApp=${this.coreApp} + featureGroups=${this.featureGroups?.joinToString { it.features?.joinToString { featureInfo -> featureInfo.dumpToString() }.orEmpty() }} + firstInstallTime=${this.firstInstallTime} + gids=${gids?.contentToString()} + installLocation=${this.installLocation} + instrumentation=${instrumentation?.joinToString { it.dumpToString() }} + isApex=${this.isApex} + isStub=${this.isStub} + lastUpdateTime=${this.lastUpdateTime} + mOverlayIsStatic=${this.mOverlayIsStatic} + overlayCategory=${this.overlayCategory} + overlayPriority=${this.overlayPriority} + overlayTarget=${this.overlayTarget} + packageName=${this.packageName} + permissions=${this.permissions?.joinToString { it.dumpToString() }} + providers=${this.providers?.joinToString { it.dumpToString() }} + receivers=${this.receivers?.joinToString { it.dumpToString() }} + reqFeatures=${this.reqFeatures?.joinToString { it.dumpToString() }} + requestedPermissions=${this.requestedPermissions?.contentToString()} + requestedPermissionsFlags=${this.requestedPermissionsFlags?.contentToString()} + requiredAccountType=${this.requiredAccountType} + requiredForAllUsers=${this.requiredForAllUsers} + restrictedAccountType=${this.restrictedAccountType} + services=${this.services?.contentToString()} + sharedUserId=${this.sharedUserId} + sharedUserLabel=${this.sharedUserLabel} + signatures=${this.signatures?.joinToString { it.toCharsString() }} + signingInfo=${this.signingInfo?.signingCertificateHistory?.joinToString { it.toCharsString() }.orEmpty()} + splitNames=${this.splitNames?.contentToString()} + splitRevisionCodes=${this.splitRevisionCodes?.contentToString()} + targetOverlayableName=${this.targetOverlayableName} + versionCode=${this.versionCode} + versionCodeMajor=${this.versionCodeMajor} + versionName=${this.versionName} + """.trimIndent() + + @Suppress("unused") + private fun <T> SparseArray<T>.sequence(): Sequence<Pair<Int, T>> { + var index = 0 + return generateSequence { + index++.takeIf { it < size() }?.let { keyAt(it) to valueAt(index) } + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java index 270436d65614..cb49fefb8047 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java @@ -50,7 +50,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; -import java.util.Objects; /** * White-box unit tests for {@link TimeZoneDetectorStrategy}. @@ -445,8 +444,7 @@ public class TimeZoneDetectorStrategyTest { static class FakeTimeZoneDetectorStrategyCallback implements TimeZoneDetectorStrategy.Callback { private boolean mAutoTimeZoneDetectionEnabled; - private TestState<TimeZoneChange> mTimeZoneChanges = new TestState<>(); - private String mTimeZoneId; + private TestState<String> mTimeZoneId = new TestState<>(); @Override public boolean isAutoTimeZoneDetectionEnabled() { @@ -460,13 +458,12 @@ public class TimeZoneDetectorStrategyTest { @Override public String getDeviceTimeZone() { - return mTimeZoneId; + return mTimeZoneId.getLatest(); } @Override - public void setDeviceTimeZone(String zoneId, boolean withNetworkBroadcast) { - mTimeZoneId = zoneId; - mTimeZoneChanges.set(new TimeZoneChange(zoneId, withNetworkBroadcast)); + public void setDeviceTimeZone(String zoneId) { + mTimeZoneId.set(zoneId); } void initializeAutoTimeZoneDetection(boolean enabled) { @@ -474,7 +471,7 @@ public class TimeZoneDetectorStrategyTest { } void initializeTimeZone(String zoneId) { - mTimeZoneId = zoneId; + mTimeZoneId.init(zoneId); } void setAutoTimeZoneDetectionEnabled(boolean enabled) { @@ -482,46 +479,17 @@ public class TimeZoneDetectorStrategyTest { } void assertTimeZoneNotSet() { - mTimeZoneChanges.assertHasNotBeenSet(); + mTimeZoneId.assertHasNotBeenSet(); } - void assertTimeZoneSet(String timeZoneId, boolean withNetworkBroadcast) { - mTimeZoneChanges.assertHasBeenSet(); - mTimeZoneChanges.assertChangeCount(1); - TimeZoneChange expectedChange = new TimeZoneChange(timeZoneId, withNetworkBroadcast); - mTimeZoneChanges.assertLatestEquals(expectedChange); + void assertTimeZoneSet(String timeZoneId) { + mTimeZoneId.assertHasBeenSet(); + mTimeZoneId.assertChangeCount(1); + mTimeZoneId.assertLatestEquals(timeZoneId); } void commitAllChanges() { - mTimeZoneChanges.commitLatest(); - } - } - - private static class TimeZoneChange { - private final String mTimeZoneId; - private final boolean mWithNetworkBroadcast; - - private TimeZoneChange(String timeZoneId, boolean withNetworkBroadcast) { - mTimeZoneId = timeZoneId; - mWithNetworkBroadcast = withNetworkBroadcast; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TimeZoneChange that = (TimeZoneChange) o; - return mWithNetworkBroadcast == that.mWithNetworkBroadcast - && mTimeZoneId.equals(that.mTimeZoneId); - } - - @Override - public int hashCode() { - return Objects.hash(mTimeZoneId, mWithNetworkBroadcast); + mTimeZoneId.commitLatest(); } } @@ -614,21 +582,13 @@ public class TimeZoneDetectorStrategyTest { } Script verifyTimeZoneSetAndReset(PhoneTimeZoneSuggestion suggestion) { - // Phone suggestions should cause a TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE - // broadcast. - boolean withNetworkBroadcast = true; - mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet( - suggestion.getZoneId(), withNetworkBroadcast); + mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(suggestion.getZoneId()); mFakeTimeZoneDetectorStrategyCallback.commitAllChanges(); return this; } Script verifyTimeZoneSetAndReset(ManualTimeZoneSuggestion suggestion) { - // Manual suggestions should not cause a TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE - // broadcast. - boolean withNetworkBroadcast = false; - mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet( - suggestion.getZoneId(), withNetworkBroadcast); + mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(suggestion.getZoneId()); mFakeTimeZoneDetectorStrategyCallback.commitAllChanges(); return this; } diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp index 92198fa8cb0c..f608babd062c 100644 --- a/services/tests/uiservicestests/Android.bp +++ b/services/tests/uiservicestests/Android.bp @@ -20,6 +20,7 @@ android_test { "androidx.test.rules", "hamcrest-library", "mockito-target-inline-minus-junit4", "platform-test-annotations", + "platformprotosnano", "hamcrest-library", "testables", "truth-prebuilt", diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java new file mode 100644 index 000000000000..f685c68f4160 --- /dev/null +++ b/services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.android.server.notification; + +import static com.android.server.notification.NotificationManagerService.REPORT_REMOTE_VIEWS; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotSame; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.service.notification.nano.NotificationRemoteViewsProto; +import android.test.MoreAsserts; +import android.util.proto.ProtoOutputStream; + +import androidx.test.filters.SmallTest; + +import com.android.server.UiServiceTestCase; + +import com.google.protobuf.nano.InvalidProtocolBufferNanoException; + +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.List; + +@SmallTest +public class PulledStatsTest extends UiServiceTestCase { + + @Test + public void testPulledStats_Empty() { + PulledStats stats = new PulledStats(0L); + assertEquals(0L, stats.endTimeMs()); + } + + @Test + public void testPulledStats_UnknownReport() { + PulledStats stats = new PulledStats(0L); + stats.addUndecoratedPackage("foo", 456); + stats.addUndecoratedPackage("bar", 123); + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + final ProtoOutputStream proto = new ProtoOutputStream(bytes); + stats.writeToProto(1023123, proto); // a very large number + proto.flush(); + + // expect empty output in response to an unrecognized request + assertEquals(0L, bytes.size()); + } + + @Test + public void testPulledStats_RemoteViewReportPackages() { + List<String> expectedPkgs = new ArrayList<>(2); + expectedPkgs.add("foo"); + expectedPkgs.add("bar"); + + PulledStats stats = new PulledStats(0L); + for(String pkg: expectedPkgs) { + stats.addUndecoratedPackage(pkg, 111); + } + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + final ProtoOutputStream protoStream = new ProtoOutputStream(bytes); + stats.writeToProto(REPORT_REMOTE_VIEWS, protoStream); + protoStream.flush(); + + try { + NotificationRemoteViewsProto proto = + NotificationRemoteViewsProto.parseFrom(bytes.toByteArray()); + List<String> actualPkgs = new ArrayList<>(2); + for(int i = 0 ; i < proto.packageRemoteViewInfo.length; i++) { + actualPkgs.add(proto.packageRemoteViewInfo[i].packageName); + } + assertEquals(2, actualPkgs.size()); + assertTrue("missing packages", actualPkgs.containsAll(expectedPkgs)); + assertTrue("unexpected packages", expectedPkgs.containsAll(actualPkgs)); + } catch (InvalidProtocolBufferNanoException e) { + e.printStackTrace(); + fail("writeToProto generated unparsable output"); + } + + } + @Test + public void testPulledStats_RemoteViewReportEndTime() { + List<String> expectedPkgs = new ArrayList<>(2); + expectedPkgs.add("foo"); + expectedPkgs.add("bar"); + + PulledStats stats = new PulledStats(0L); + long t = 111; + for(String pkg: expectedPkgs) { + t += 1000; + stats.addUndecoratedPackage(pkg, t); + } + assertEquals(t, stats.endTimeMs()); + } + +} diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp index cdba9a10fa82..cd4f0daa8ebc 100644 --- a/services/tests/wmtests/Android.bp +++ b/services/tests/wmtests/Android.bp @@ -13,7 +13,7 @@ android_test { ], static_libs: [ - "frameworks-base-testutils", + "frameworks-base-testutils-minus-mockito", "services.core", "androidx.test.runner", "androidx.test.rules", diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 7166829e01da..dbcfa94c69bf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -203,7 +203,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // An activity can be launched on default display. assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY)); // An activity cannot be launched on a non-existent display. - assertFalse(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY + 1)); + assertFalse(activity.canBeLaunchedOnDisplay(Integer.MAX_VALUE)); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java index 4d2183b32392..856641228d80 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java @@ -80,6 +80,9 @@ import java.nio.charset.StandardCharsets; @RunWith(WindowTestRunner.class) public class DisplayWindowSettingsTests extends WindowTestsBase { + private static final byte DISPLAY_PORT = (byte) 0xFF; + private static final long DISPLAY_MODEL = 0xEEEEEEEEL; + private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir(); private DisplayWindowSettings mTarget; @@ -479,10 +482,11 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { @Test public void testReadingDisplaySettingsFromStorage_UsePortAsId() { - final DisplayAddress.Physical displayAddress = DisplayAddress.fromPhysicalDisplayId(123456); + final DisplayAddress.Physical displayAddress = + DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL); mPrimaryDisplay.getDisplayInfo().address = displayAddress; - final String displayIdentifier = "port:" + displayAddress.getPort(); + final String displayIdentifier = "port:" + Byte.toUnsignedInt(DISPLAY_PORT); prepareDisplaySettings(displayIdentifier, true /* usePortAsId */); readAndAssertDisplaySettings(mPrimaryDisplay); @@ -521,7 +525,8 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { @Test public void testWritingDisplaySettingsToStorage_UsePortAsId() throws Exception { // Store config to use port as identifier. - final DisplayAddress.Physical displayAddress = DisplayAddress.fromPhysicalDisplayId(123456); + final DisplayAddress.Physical displayAddress = + DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL); mSecondaryDisplay.getDisplayInfo().address = displayAddress; prepareDisplaySettings(null /* displayIdentifier */, true /* usePortAsId */); @@ -532,7 +537,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { assertTrue(mStorage.wasWriteSuccessful()); // Verify that settings were stored correctly. - assertEquals("Attribute value must be stored", "port:" + displayAddress.getPort(), + assertEquals("Attribute value must be stored", "port:" + Byte.toUnsignedInt(DISPLAY_PORT), getStoredDisplayAttributeValue("name")); assertEquals("Attribute value must be stored", "true", getStoredDisplayAttributeValue("shouldShowSystemDecors")); diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 212931b76b88..8953cd4cddcf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; @@ -27,7 +26,7 @@ import static android.view.Surface.ROTATION_90; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; @@ -36,7 +35,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.ActivityManagerInternal; @@ -54,7 +52,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; -import java.util.concurrent.TimeUnit; /** * Tests for Size Compatibility mode. @@ -265,7 +262,8 @@ public class SizeCompatTests extends ActivityTestsBase { setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build()); prepareUnresizable(1.4f /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE); - assertTrue(mActivity.inSizeCompatMode()); + // The display aspect ratio 2.5 > 1.4 (max of activity), so the size is fitted. + assertFalse(mActivity.inSizeCompatMode()); final Rect originalBounds = new Rect(mActivity.getBounds()); final Rect originalAppBounds = new Rect(mActivity.getWindowConfiguration().getAppBounds()); @@ -317,37 +315,35 @@ public class SizeCompatTests extends ActivityTestsBase { @Test public void testResetNonVisibleActivity() { setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build()); + prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED); final ActivityDisplay display = mStack.getDisplay(); - spyOn(display); + // Resize the display so the activity is in size compatibility mode. + resizeDisplay(display, 900, 1800); - prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED); mActivity.setState(STOPPED, "testSizeCompatMode"); mActivity.mVisibleRequested = false; mActivity.app.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY); - // Make the parent bounds to be different so the activity is in size compatibility mode. - mTask.getWindowConfiguration().setAppBounds(new Rect(0, 0, 600, 1200)); // Simulate the display changes orientation. - when(display.getLastOverrideConfigurationChanges()).thenReturn( - ActivityInfo.CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION - | ActivityInfo.CONFIG_WINDOW_CONFIGURATION); - mActivity.onConfigurationChanged(mTask.getConfiguration()); - when(display.getLastOverrideConfigurationChanges()).thenCallRealMethod(); - // The override configuration should not change so it is still in size compatibility mode. + final Configuration c = new Configuration(); + display.getDisplayRotation().setRotation(ROTATION_90); + display.computeScreenConfiguration(c); + display.onRequestedOverrideConfigurationChanged(c); + // Size compatibility mode is able to handle orientation change so the process shouldn't be + // restarted and the override configuration won't be cleared. + verify(mActivity, never()).restartProcessIfVisible(); assertTrue(mActivity.inSizeCompatMode()); // Change display density - final DisplayContent displayContent = mStack.getDisplay().mDisplayContent; - displayContent.mBaseDisplayDensity = (int) (0.7f * displayContent.mBaseDisplayDensity); - final Configuration c = new Configuration(); - displayContent.computeScreenConfiguration(c); + display.mBaseDisplayDensity = (int) (0.7f * display.mBaseDisplayDensity); + display.computeScreenConfiguration(c); mService.mAmInternal = mock(ActivityManagerInternal.class); - mStack.getDisplay().onRequestedOverrideConfigurationChanged(c); + display.onRequestedOverrideConfigurationChanged(c); // The override configuration should be reset and the activity's process will be killed. assertFalse(mActivity.inSizeCompatMode()); verify(mActivity).restartProcessIfVisible(); - mLockRule.runWithScissors(mService.mH, () -> { }, TimeUnit.SECONDS.toMillis(3)); + waitHandlerIdle(mService.mH); verify(mService.mAmInternal).killProcess( eq(mActivity.app.mName), eq(mActivity.app.mUid), anyString()); } @@ -362,7 +358,6 @@ public class SizeCompatTests extends ActivityTestsBase { ActivityRecord activity = mActivity; activity.setState(ActivityStack.ActivityState.RESUMED, "testHandleActivitySizeCompatMode"); prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); - ensureActivityConfiguration(); assertFalse(mActivity.inSizeCompatMode()); final ArrayList<IBinder> compatTokens = new ArrayList<>(); diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index d3b68e02cbf8..a172b656be0c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -287,6 +287,10 @@ public class SystemServicesTestRule implements TestRule { // Mock root, some default display, and home stack. spyOn(mWmService.mRoot); final ActivityDisplay display = mAtmService.mRootActivityContainer.getDefaultDisplay(); + // Set default display to be in fullscreen mode. Devices with PC feature may start their + // default display in freeform mode but some of tests in WmTests have implicit assumption on + // that the default display is in fullscreen mode. + display.setDisplayWindowingMode(WINDOWING_MODE_FULLSCREEN); spyOn(display); spyOn(display.mDisplayContent); final ActivityStack homeStack = display.getStack( diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java index e34824c57fb2..ef9a73b794f7 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java +++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java @@ -229,14 +229,14 @@ public class UsageStatsDatabase { } try { - IntervalStats stats = new IntervalStats(); for (int i = start; i < fileCount - 1; i++) { + final IntervalStats stats = new IntervalStats(); readLocked(files.valueAt(i), stats); if (!checkinAction.checkin(stats)) { return false; } } - } catch (IOException e) { + } catch (Exception e) { Slog.e(TAG, "Failed to check-in", e); return false; } @@ -744,7 +744,7 @@ public class UsageStatsDatabase { IntervalStats stats = new IntervalStats(); readLocked(f, stats); return stats; - } catch (IOException e) { + } catch (Exception e) { Slog.e(TAG, "Failed to read usage stats file", e); } } @@ -848,10 +848,10 @@ public class UsageStatsDatabase { } } - final IntervalStats stats = new IntervalStats(); final ArrayList<T> results = new ArrayList<>(); for (int i = startIndex; i <= endIndex; i++) { final AtomicFile f = intervalStats.valueAt(i); + final IntervalStats stats = new IntervalStats(); if (DEBUG) { Slog.d(TAG, "Reading stat file " + f.getBaseFile().getAbsolutePath()); @@ -862,7 +862,7 @@ public class UsageStatsDatabase { if (beginTime < stats.endTime) { combiner.combine(stats, false, results); } - } catch (IOException e) { + } catch (Exception e) { Slog.e(TAG, "Failed to read usage stats file", e); // We continue so that we return results that are not // corrupt. @@ -1009,7 +1009,8 @@ public class UsageStatsDatabase { } } - private void writeLocked(AtomicFile file, IntervalStats stats) throws IOException { + private void writeLocked(AtomicFile file, IntervalStats stats) + throws IOException, RuntimeException { if (mCurrentVersion <= 3) { Slog.wtf(TAG, "Attempting to write UsageStats as XML with version " + mCurrentVersion); return; @@ -1018,7 +1019,7 @@ public class UsageStatsDatabase { } private static void writeLocked(AtomicFile file, IntervalStats stats, int version, - PackagesTokenData packagesTokenData) throws IOException { + PackagesTokenData packagesTokenData) throws IOException, RuntimeException { FileOutputStream fos = file.startWrite(); try { writeLocked(fos, stats, version, packagesTokenData); @@ -1031,7 +1032,7 @@ public class UsageStatsDatabase { } private static void writeLocked(OutputStream out, IntervalStats stats, int version, - PackagesTokenData packagesTokenData) throws IOException { + PackagesTokenData packagesTokenData) throws RuntimeException { switch (version) { case 1: case 2: @@ -1041,7 +1042,7 @@ public class UsageStatsDatabase { case 4: try { UsageStatsProto.write(out, stats); - } catch (IOException | IllegalArgumentException e) { + } catch (Exception e) { Slog.e(TAG, "Unable to write interval stats to proto.", e); } break; @@ -1049,7 +1050,7 @@ public class UsageStatsDatabase { stats.obfuscateData(packagesTokenData); try { UsageStatsProtoV2.write(out, stats); - } catch (IOException | IllegalArgumentException e) { + } catch (Exception e) { Slog.e(TAG, "Unable to write interval stats to proto.", e); } break; @@ -1060,7 +1061,13 @@ public class UsageStatsDatabase { } } - private void readLocked(AtomicFile file, IntervalStats statsOut) throws IOException { + /** + * Note: the data read from the given file will add to the IntervalStats object passed into this + * method. It is up to the caller to ensure that this is the desired behavior - if not, the + * caller should ensure that the data in the reused object is being cleared. + */ + private void readLocked(AtomicFile file, IntervalStats statsOut) + throws IOException, RuntimeException { if (mCurrentVersion <= 3) { Slog.wtf(TAG, "Reading UsageStats as XML; current database version: " + mCurrentVersion); @@ -1070,9 +1077,13 @@ public class UsageStatsDatabase { /** * Returns {@code true} if any stats were omitted while reading, {@code false} otherwise. + * <p/> + * Note: the data read from the given file will add to the IntervalStats object passed into this + * method. It is up to the caller to ensure that this is the desired behavior - if not, the + * caller should ensure that the data in the reused object is being cleared. */ private static boolean readLocked(AtomicFile file, IntervalStats statsOut, int version, - PackagesTokenData packagesTokenData) throws IOException { + PackagesTokenData packagesTokenData) throws IOException, RuntimeException { boolean dataOmitted = false; try { FileInputStream in = file.openRead(); @@ -1096,9 +1107,13 @@ public class UsageStatsDatabase { /** * Returns {@code true} if any stats were omitted while reading, {@code false} otherwise. + * <p/> + * Note: the data read from the given file will add to the IntervalStats object passed into this + * method. It is up to the caller to ensure that this is the desired behavior - if not, the + * caller should ensure that the data in the reused object is being cleared. */ private static boolean readLocked(InputStream in, IntervalStats statsOut, int version, - PackagesTokenData packagesTokenData) throws IOException { + PackagesTokenData packagesTokenData) throws RuntimeException { boolean dataOmitted = false; switch (version) { case 1: @@ -1114,14 +1129,14 @@ public class UsageStatsDatabase { case 4: try { UsageStatsProto.read(in, statsOut); - } catch (IOException e) { + } catch (Exception e) { Slog.e(TAG, "Unable to read interval stats from proto.", e); } break; case 5: try { UsageStatsProtoV2.read(in, statsOut); - } catch (IOException e) { + } catch (Exception e) { Slog.e(TAG, "Unable to read interval stats from proto.", e); } dataOmitted = statsOut.deobfuscateData(packagesTokenData); @@ -1145,7 +1160,7 @@ public class UsageStatsDatabase { try (FileInputStream in = new AtomicFile(mPackageMappingsFile).openRead()) { UsageStatsProtoV2.readObfuscatedData(in, mPackagesTokenData); - } catch (IOException e) { + } catch (Exception e) { Slog.e(TAG, "Failed to read the obfuscated packages mapping file.", e); return; } @@ -1174,7 +1189,7 @@ public class UsageStatsDatabase { UsageStatsProtoV2.writeObfuscatedData(fos, mPackagesTokenData); file.finishWrite(fos); fos = null; - } catch (IOException | IllegalArgumentException e) { + } catch (Exception e) { Slog.e(TAG, "Unable to write obfuscated data to proto.", e); } finally { file.failWrite(fos); @@ -1414,8 +1429,8 @@ public class UsageStatsDatabase { try { stats.beginTime = in.readLong(); readLocked(in, stats, version, mPackagesTokenData); - } catch (IOException ioe) { - Slog.d(TAG, "DeSerializing IntervalStats Failed", ioe); + } catch (Exception e) { + Slog.d(TAG, "DeSerializing IntervalStats Failed", e); stats = null; } return stats; diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 064922386773..c900f386b438 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -653,18 +653,20 @@ public class UsageStatsService extends SystemService implements } Arrays.sort(pendingEventsFiles); - for (int i = 0; i < pendingEventsFiles.length; i++) { + final int numFiles = pendingEventsFiles.length; + for (int i = 0; i < numFiles; i++) { final AtomicFile af = new AtomicFile(pendingEventsFiles[i]); + final LinkedList<Event> tmpEvents = new LinkedList<>(); try { try (FileInputStream in = af.openRead()) { - UsageStatsProtoV2.readPendingEvents(in, pendingEvents); + UsageStatsProtoV2.readPendingEvents(in, tmpEvents); } - } catch (IOException e) { - // Even if one file read fails, exit here to keep all events in order on disk - - // they will be read and processed the next time user is unlocked. + // only add to the pending events if the read was successful + pendingEvents.addAll(tmpEvents); + } catch (Exception e) { + // Most likely trying to read a corrupted file - log the failure and continue + // reading the other pending event files. Slog.e(TAG, "Could not read " + pendingEventsFiles[i] + " for user " + userId); - pendingEvents.clear(); - return; } } } @@ -691,7 +693,7 @@ public class UsageStatsService extends SystemService implements af.finishWrite(fos); fos = null; pendingEvents.clear(); - } catch (IOException | IllegalArgumentException e) { + } catch (Exception e) { Slog.e(TAG, "Failed to write " + pendingEventsFile.getAbsolutePath() + " for user " + userId); } finally { diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java index f89bbc7d179a..73faf9f5f9f4 100644 --- a/telephony/java/android/telephony/Annotation.java +++ b/telephony/java/android/telephony/Annotation.java @@ -463,9 +463,7 @@ public class Annotation { DataFailCause.UNKNOWN, DataFailCause.RADIO_NOT_AVAILABLE, DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER, - DataFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN, DataFailCause.LOST_CONNECTION, - DataFailCause.RESET_BY_FRAMEWORK }) @Retention(RetentionPolicy.SOURCE) public @interface DataFailureCause { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 1b86c09ce86c..2df0ccac008b 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2092,12 +2092,6 @@ public class CarrierConfigManager { "allow_metered_network_for_cert_download_bool"; /** - * Carrier specified WiFi networks. - * @hide - */ - public static final String KEY_CARRIER_WIFI_STRING_ARRAY = "carrier_wifi_string_array"; - - /** * Time delay (in ms) after which we show the notification to switch the preferred * network. * @hide @@ -2326,7 +2320,7 @@ public class CarrierConfigManager { * Reference: 3GPP TS 38.215 * * 4 threshold integers must be within the boundaries [-20 dB, -3 dB], and the levels are: - * "NONE: [-23, threshold1]" + * "NONE: [-20, threshold1]" * "POOR: (threshold1, threshold2]" * "MODERATE: (threshold2, threshold3]" * "GOOD: (threshold3, threshold4]" @@ -2360,15 +2354,26 @@ public class CarrierConfigManager { /** * Bit-field integer to determine whether to use SS reference signal received power (SSRSRP), * SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference - * ratio (SSSINR) for the number of 5G NR signal bars. If multiple measures are set bit, the - * parameter whose value is smallest is used to indicate the signal bar. + * ratio (SSSINR) for the number of 5G NR signal bars and signal criteria reporting enabling. + * + * <p> If a measure is not set, signal criteria reporting from modem will not be triggered and + * not be used for calculating signal level. If multiple measures are set bit, the parameter + * whose value is smallest is used to indicate the signal level. * * SSRSRP = 1 << 0, * SSRSRQ = 1 << 1, * SSSINR = 1 << 2, * + * The value of this key must be bitwise OR of {@link CellSignalStrengthNr#USE_SSRSRP}, + * {@link CellSignalStrengthNr#USE_SSRSRQ}, {@link CellSignalStrengthNr#USE_SSSINR}. + * + * For example, if both SSRSRP and SSSINR are used, the value of key is 5 (1 << 0 | 1 << 2). + * If the key is invalid or not configured, a default value (SSRSRP = 1 << 0) will apply. + * * Reference: 3GPP TS 38.215, * 3GPP TS 38.133 10.1.16.1 + * + * @hide */ public static final String KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT = "parameters_use_for_5g_nr_signal_bar_int"; @@ -3183,59 +3188,6 @@ public class CarrierConfigManager { } } - /** - * Wi-Fi configs used in Carrier Wi-Fi application. - * - * @hide - */ - @SystemApi - public static final class Wifi { - /** Prefix of all Wifi.KEY_* constants. */ - public static final String KEY_PREFIX = "wifi."; - - /** - * Whenever any information under wifi namespace is changed, the version should be - * incremented by 1 so that the device is able to figure out the latest profiles based on - * the version. - */ - public static final String KEY_CARRIER_PROFILES_VERSION_INT = - KEY_PREFIX + "carrier_profiles_version_int"; - - /** - * It contains the package name of connection manager that the carrier owns. - * - * <P>Once it is installed, the profiles installed by Carrier Wi-Fi Application - * will be deleted. - * Once it is uninstalled, Carrier Wi-Fi Application will re-install the latest profiles. - */ - public static final String KEY_CARRIER_CONNECTION_MANAGER_PACKAGE_STRING = - KEY_PREFIX + "carrier_connection_manager_package_string"; - /** - * It is to have the list of wifi networks profiles which contain the information about - * the wifi-networks to which carrier wants the device to connect. - */ - public static final String KEY_NETWORK_PROFILES_STRING_ARRAY = - KEY_PREFIX + "network_profiles_string_array"; - - /** - * It is to have the list of Passpoint profiles which contain the information about - * the Passpoint networks to which carrier wants the device to connect. - */ - public static final String KEY_PASSPOINT_PROFILES_STRING_ARRAY = - KEY_PREFIX + "passpoint_profiles_string_array"; - - private static PersistableBundle getDefaults() { - PersistableBundle defaults = new PersistableBundle(); - defaults.putInt(KEY_CARRIER_PROFILES_VERSION_INT, -1); - defaults.putString(KEY_CARRIER_CONNECTION_MANAGER_PACKAGE_STRING, null); - defaults.putStringArray(KEY_NETWORK_PROFILES_STRING_ARRAY, null); - defaults.putStringArray(KEY_PASSPOINT_PROFILES_STRING_ARRAY, null); - return defaults; - } - - private Wifi() {} - } - /** * An int array containing CDMA enhanced roaming indicator values for Home (non-roaming) network. * The default values come from 3GPP2 C.R1001 table 8.1-1. @@ -3688,7 +3640,6 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL, false); sDefaults.putBoolean(KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL, false); sDefaults.putBoolean(KEY_HIDE_DIGITS_HELPER_TEXT_ON_STK_INPUT_SCREEN_BOOL, true); - sDefaults.putStringArray(KEY_CARRIER_WIFI_STRING_ARRAY, null); sDefaults.putInt(KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT, -1); sDefaults.putInt(KEY_EMERGENCY_NOTIFICATION_DELAY_INT, -1); sDefaults.putBoolean(KEY_ALLOW_USSD_REQUESTS_VIA_TELEPHONY_MANAGER_BOOL, true); @@ -3748,6 +3699,32 @@ public class CarrierConfigManager { -95, /* SIGNAL_STRENGTH_GOOD */ -85 /* SIGNAL_STRENGTH_GREAT */ }); + sDefaults.putIntArray(KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY, + // Boundaries: [-140 dB, -44 dB] + new int[] { + -125, /* SIGNAL_STRENGTH_POOR */ + -115, /* SIGNAL_STRENGTH_MODERATE */ + -105, /* SIGNAL_STRENGTH_GOOD */ + -95, /* SIGNAL_STRENGTH_GREAT */ + }); + sDefaults.putIntArray(KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY, + // Boundaries: [-20 dB, -3 dB] + new int[] { + -14, /* SIGNAL_STRENGTH_POOR */ + -12, /* SIGNAL_STRENGTH_MODERATE */ + -10, /* SIGNAL_STRENGTH_GOOD */ + -8 /* SIGNAL_STRENGTH_GREAT */ + }); + sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY, + // Boundaries: [-23 dB, 40 dB] + new int[] { + -8, /* SIGNAL_STRENGTH_POOR */ + 0, /* SIGNAL_STRENGTH_MODERATE */ + 8, /* SIGNAL_STRENGTH_GOOD */ + 16 /* SIGNAL_STRENGTH_GREAT */ + }); + sDefaults.putInt(KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, + CellSignalStrengthNr.USE_SSRSRP); sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "rssi"); sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false); sDefaults.putBoolean(KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL, false); @@ -3791,7 +3768,6 @@ public class CarrierConfigManager { /* Default value is 60 seconds. */ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG, 60000); sDefaults.putAll(Gps.getDefaults()); - sDefaults.putAll(Wifi.getDefaults()); sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY, new int[] { 1 /* Roaming Indicator Off */ @@ -3876,6 +3852,34 @@ public class CarrierConfigManager { @SystemApi @TestApi public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrideValues) { + overrideConfig(subscriptionId, overrideValues, false); + } + + /** + * Overrides the carrier config of the provided subscription ID with the provided values. + * + * Any further queries to carrier config from any process will return the overridden values + * after this method returns. The overrides are effective until the user passes in {@code null} + * for {@code overrideValues}. This removes all previous overrides and sets the carrier config + * back to production values. + * + * The overrides is stored persistently and will survive a reboot if {@code persistent} is true. + * + * May throw an {@link IllegalArgumentException} if {@code overrideValues} contains invalid + * values for the specified config keys. + * + * NOTE: This API is meant for testing purposes only. + * + * @param subscriptionId The subscription ID for which the override should be done. + * @param overrideValues Key-value pairs of the values that are to be overridden. If set to + * {@code null}, this will remove all previous overrides and set the + * carrier configuration back to production values. + * @param persistent Determines whether the override should be persistent. + * @hide + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrideValues, + boolean persistent) { try { ICarrierConfigLoader loader = getICarrierConfigLoader(); if (loader == null) { @@ -3883,7 +3887,7 @@ public class CarrierConfigManager { + " ICarrierConfigLoader is null"); return; } - loader.overrideConfig(subscriptionId, overrideValues); + loader.overrideConfig(subscriptionId, overrideValues, persistent); } catch (RemoteException ex) { Rlog.e(TAG, "Error setting config for subId " + subscriptionId + ": " + ex.toString()); diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java index f9b7f6dbc193..f31fafe36508 100644 --- a/telephony/java/android/telephony/CellSignalStrengthNr.java +++ b/telephony/java/android/telephony/CellSignalStrengthNr.java @@ -16,11 +16,15 @@ package android.telephony; +import android.annotation.IntDef; import android.annotation.IntRange; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; import java.util.Objects; /** @@ -36,13 +40,67 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa private static final String TAG = "CellSignalStrengthNr"; + // Lifted from Default carrier configs and max range of SSRSRP + // Boundaries: [-140 dB, -44 dB] + private int[] mSsRsrpThresholds = new int[] { + -125, /* SIGNAL_STRENGTH_POOR */ + -115, /* SIGNAL_STRENGTH_MODERATE */ + -105, /* SIGNAL_STRENGTH_GOOD */ + -95, /* SIGNAL_STRENGTH_GREAT */ + }; + + // Lifted from Default carrier configs and max range of SSRSRQ + // Boundaries: [-20 dB, -3 dB] + private int[] mSsRsrqThresholds = new int[] { + -14, /* SIGNAL_STRENGTH_POOR */ + -12, /* SIGNAL_STRENGTH_MODERATE */ + -10, /* SIGNAL_STRENGTH_GOOD */ + -8 /* SIGNAL_STRENGTH_GREAT */ + }; + + // Lifted from Default carrier configs and max range of SSSINR + // Boundaries: [-23 dB, 40 dB] + private int[] mSsSinrThresholds = new int[] { + -8, /* SIGNAL_STRENGTH_POOR */ + 0, /* SIGNAL_STRENGTH_MODERATE */ + 8, /* SIGNAL_STRENGTH_GOOD */ + 16 /* SIGNAL_STRENGTH_GREAT */ + }; + + /** + * Indicates SSRSRP is considered for {@link #getLevel()} and reporting from modem. + * + * @hide + */ + public static final int USE_SSRSRP = 1 << 0; + /** + * Indicates SSRSRQ is considered for {@link #getLevel()} and reporting from modem. + * + * @hide + */ + public static final int USE_SSRSRQ = 1 << 1; /** - * These threshold values are copied from LTE. - * TODO: make it configurable via CarrierConfig. + * Indicates SSSINR is considered for {@link #getLevel()} and reporting from modem. + * + * @hide */ - private static final int SIGNAL_GREAT_THRESHOLD = -95; - private static final int SIGNAL_GOOD_THRESHOLD = -105; - private static final int SIGNAL_MODERATE_THRESHOLD = -115; + public static final int USE_SSSINR = 1 << 2; + + /** + * Bit-field integer to determine whether to use SS reference signal received power (SSRSRP), + * SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference + * ratio (SSSINR) for the number of 5G NR signal bars. If multiple measures are set bit, the + * parameter whose value is smallest is used to indicate the signal bar. + * + * @hide + */ + @IntDef(flag = true, prefix = { "USE_" }, value = { + USE_SSRSRP, + USE_SSRSRQ, + USE_SSSINR + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SignalLevelAndReportCriteriaSource {} private int mCsiRsrp; private int mCsiRsrq; @@ -52,6 +110,21 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa private int mSsSinr; private int mLevel; + /** + * Bit-field integer to determine whether to use SS reference signal received power (SSRSRP), + * SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference + * ratio (SSSINR) for the number of 5G NR signal bars. If multiple measures are set bit, the + * parameter whose value is smallest is used to indicate the signal bar. + * + * SSRSRP = 1 << 0, + * SSRSRQ = 1 << 1, + * SSSINR = 1 << 2, + * + * For example, if both SSRSRP and SSSINR are used, the value of key is 5 (1 << 0 | 1 << 2). + * If the key is invalid or not configured, a default value (SSRSRP = 1 << 0) will apply. + */ + private int mParametersUseForLevel; + /** @hide */ public CellSignalStrengthNr() { setDefaultValues(); @@ -182,6 +255,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa mSsRsrq = CellInfo.UNAVAILABLE; mSsSinr = CellInfo.UNAVAILABLE; mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; + mParametersUseForLevel = USE_SSRSRP; } /** {@inheritDoc} */ @@ -191,20 +265,83 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa return mLevel; } + /** + * Checks if the given parameter type is considered to use for {@link #getLevel()}. + * + * Note: if multiple parameter types are considered, the smaller level for one of the + * parameters would be returned by {@link #getLevel()} + * + * @param parameterType bitwise OR of {@link #USE_SSRSRP}, {@link #USE_SSRSRQ}, + * {@link #USE_SSSINR} + * @return {@code true} if the level is calculated based on the given parameter type; + * {@code false} otherwise. + * + */ + private boolean isLevelForParameter(@SignalLevelAndReportCriteriaSource int parameterType) { + return (parameterType & mParametersUseForLevel) == parameterType; + } + /** @hide */ @Override public void updateLevel(PersistableBundle cc, ServiceState ss) { - if (mSsRsrp == CellInfo.UNAVAILABLE) { - mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; - } else if (mSsRsrp >= SIGNAL_GREAT_THRESHOLD) { - mLevel = SIGNAL_STRENGTH_GREAT; - } else if (mSsRsrp >= SIGNAL_GOOD_THRESHOLD) { - mLevel = SIGNAL_STRENGTH_GOOD; - } else if (mSsRsrp >= SIGNAL_MODERATE_THRESHOLD) { - mLevel = SIGNAL_STRENGTH_MODERATE; + if (cc == null) { + mParametersUseForLevel = USE_SSRSRP; + } else { + mParametersUseForLevel = cc.getInt( + CarrierConfigManager.KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, USE_SSRSRP); + Rlog.i(TAG, "Using SSRSRP for Level."); + mSsRsrpThresholds = cc.getIntArray( + CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY); + Rlog.i(TAG, "Applying 5G NR SSRSRP Thresholds: " + Arrays.toString(mSsRsrpThresholds)); + mSsRsrqThresholds = cc.getIntArray( + CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY); + Rlog.i(TAG, "Applying 5G NR SSRSRQ Thresholds: " + Arrays.toString(mSsRsrqThresholds)); + mSsSinrThresholds = cc.getIntArray( + CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY); + Rlog.i(TAG, "Applying 5G NR SSSINR Thresholds: " + Arrays.toString(mSsSinrThresholds)); + } + int ssRsrpLevel = SignalStrength.INVALID; + int ssRsrqLevel = SignalStrength.INVALID; + int ssSinrLevel = SignalStrength.INVALID; + if (isLevelForParameter(USE_SSRSRP)) { + ssRsrpLevel = updateLevelWithMeasure(mSsRsrp, mSsRsrpThresholds); + Rlog.i(TAG, "Updated 5G NR SSRSRP Level: " + ssRsrpLevel); + } + if (isLevelForParameter(USE_SSRSRQ)) { + ssRsrqLevel = updateLevelWithMeasure(mSsRsrq, mSsRsrqThresholds); + Rlog.i(TAG, "Updated 5G NR SSRSRQ Level: " + ssRsrqLevel); + } + if (isLevelForParameter(USE_SSSINR)) { + ssSinrLevel = updateLevelWithMeasure(mSsSinr, mSsSinrThresholds); + Rlog.i(TAG, "Updated 5G NR SSSINR Level: " + ssSinrLevel); + } + // Apply the smaller value among three levels of three measures. + mLevel = Math.min(Math.min(ssRsrpLevel, ssRsrqLevel), ssSinrLevel); + } + + /** + * Update level with corresponding measure and thresholds. + * + * @param measure corresponding signal measure + * @param thresholds corresponding signal thresholds + * @return level of the signal strength + */ + private int updateLevelWithMeasure(int measure, int[] thresholds) { + int level; + if (measure == CellInfo.UNAVAILABLE) { + level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; + } else if (measure > thresholds[3]) { + level = SIGNAL_STRENGTH_GREAT; + } else if (measure > thresholds[2]) { + level = SIGNAL_STRENGTH_GOOD; + } else if (measure > thresholds[1]) { + level = SIGNAL_STRENGTH_MODERATE; + } else if (measure > thresholds[0]) { + level = SIGNAL_STRENGTH_POOR; } else { - mLevel = SIGNAL_STRENGTH_POOR; + level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } + return level; } /** @@ -247,6 +384,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa mSsRsrq = s.mSsRsrq; mSsSinr = s.mSsSinr; mLevel = s.mLevel; + mParametersUseForLevel = s.mParametersUseForLevel; } /** @hide */ @@ -290,6 +428,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa .append(" ssRsrq = " + mSsRsrq) .append(" ssSinr = " + mSsSinr) .append(" level = " + mLevel) + .append(" parametersUseForLevel = " + mParametersUseForLevel) .append(" }") .toString(); } diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java index 7bdf1f57f8b2..e1c4bef0dd65 100644 --- a/telephony/java/android/telephony/DataFailCause.java +++ b/telephony/java/android/telephony/DataFailCause.java @@ -950,14 +950,10 @@ public final class DataFailCause { public static final int UNKNOWN = 0x10000; /** Data fail due to radio not unavailable. */ public static final int RADIO_NOT_AVAILABLE = 0x10001; /* no retry */ - /** @hide */ + /** Data fail due to unacceptable network parameter. */ public static final int UNACCEPTABLE_NETWORK_PARAMETER = 0x10002; /* no retry */ - /** @hide */ - public static final int CONNECTION_TO_DATACONNECTIONAC_BROKEN = 0x10003; /** Data connection was lost. */ public static final int LOST_CONNECTION = 0x10004; - /** @hide */ - public static final int RESET_BY_FRAMEWORK = 0x10005; /** * Data handover failed. @@ -1361,10 +1357,7 @@ public final class DataFailCause { sFailCauseMap.put(RADIO_NOT_AVAILABLE, "RADIO_NOT_AVAILABLE"); sFailCauseMap.put(UNACCEPTABLE_NETWORK_PARAMETER, "UNACCEPTABLE_NETWORK_PARAMETER"); - sFailCauseMap.put(CONNECTION_TO_DATACONNECTIONAC_BROKEN, - "CONNECTION_TO_DATACONNECTIONAC_BROKEN"); sFailCauseMap.put(LOST_CONNECTION, "LOST_CONNECTION"); - sFailCauseMap.put(RESET_BY_FRAMEWORK, "RESET_BY_FRAMEWORK"); } private DataFailCause() { diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java new file mode 100644 index 000000000000..f6f6d75c37c6 --- /dev/null +++ b/telephony/java/android/telephony/SignalThresholdInfo.java @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.Objects; + +/** + * Defines the threshold value of the signal strength. + * @hide + */ +public class SignalThresholdInfo implements Parcelable { + /** + * Received Signal Strength Indication. + * Range: -113 dBm and -51 dBm + * Used RAN: GERAN, CDMA2000 + * Reference: 3GPP TS 27.007 section 8.5. + */ + public static final int SIGNAL_RSSI = 1; + + /** + * Received Signal Code Power. + * Range: -120 dBm to -25 dBm; + * Used RAN: UTRAN + * Reference: 3GPP TS 25.123, section 9.1.1.1 + */ + public static final int SIGNAL_RSCP = 2; + + /** + * Reference Signal Received Power. + * Range: -140 dBm to -44 dBm; + * Used RAN: EUTRAN + * Reference: 3GPP TS 36.133 9.1.4 + */ + public static final int SIGNAL_RSRP = 3; + + /** + * Reference Signal Received Quality + * Range: -20 dB to -3 dB; + * Used RAN: EUTRAN + * Reference: 3GPP TS 36.133 9.1.7 + */ + public static final int SIGNAL_RSRQ = 4; + + /** + * Reference Signal Signal to Noise Ratio + * Range: -20 dB to 30 dB; + * Used RAN: EUTRAN + */ + public static final int SIGNAL_RSSNR = 5; + + /** + * 5G SS reference signal received power. + * Range: -140 dBm to -44 dBm. + * Used RAN: NGRAN + * Reference: 3GPP TS 38.215. + */ + public static final int SIGNAL_SSRSRP = 6; + + /** + * 5G SS reference signal received quality. + * Range: -20 dB to -3 dB. + * Used RAN: NGRAN + * Reference: 3GPP TS 38.215. + */ + public static final int SIGNAL_SSRSRQ = 7; + + /** + * 5G SS signal-to-noise and interference ratio. + * Range: -23 dB to 40 dB + * Used RAN: NGRAN + * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1. + */ + public static final int SIGNAL_SSSINR = 8; + + /** @hide */ + @IntDef(prefix = { "SIGNAL_" }, value = { + SIGNAL_RSSI, + SIGNAL_RSCP, + SIGNAL_RSRP, + SIGNAL_RSRQ, + SIGNAL_RSSNR, + SIGNAL_SSRSRP, + SIGNAL_SSRSRQ, + SIGNAL_SSSINR + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SignalMeasurementType {} + + @SignalMeasurementType + private int mSignalMeasurement; + + /** + * A hysteresis time in milliseconds to prevent flapping. + * A value of 0 disables hysteresis + */ + private int mHysteresisMs; + + /** + * An interval in dB defining the required magnitude change between reports. + * hysteresisDb must be smaller than the smallest threshold delta. + * An interval value of 0 disables hysteresis. + */ + private int mHysteresisDb; + + /** + * List of threshold values. + * Range and unit must reference specific SignalMeasurementType + * The threshold values for which to apply criteria. + * A vector size of 0 disables the use of thresholds for reporting. + */ + private int[] mThresholds = null; + + /** + * {@code true} means modem must trigger the report based on the criteria; + * {@code false} means modem must not trigger the report based on the criteria. + */ + private boolean mIsEnabled = true; + + /** + * Indicates the hysteresisMs is disabled. + */ + public static final int HYSTERESIS_MS_DISABLED = 0; + + /** + * Indicates the hysteresisDb is disabled. + */ + public static final int HYSTERESIS_DB_DISABLED = 0; + + /** + * Constructor + * + * @param signalMeasurement Signal Measurement Type + * @param hysteresisMs hysteresisMs + * @param hysteresisDb hysteresisDb + * @param thresholds threshold value + * @param isEnabled isEnabled + */ + public SignalThresholdInfo(@SignalMeasurementType int signalMeasurement, + int hysteresisMs, int hysteresisDb, @NonNull int [] thresholds, boolean isEnabled) { + mSignalMeasurement = signalMeasurement; + mHysteresisMs = hysteresisMs < 0 ? HYSTERESIS_MS_DISABLED : hysteresisMs; + mHysteresisDb = hysteresisDb < 0 ? HYSTERESIS_DB_DISABLED : hysteresisDb; + mThresholds = thresholds == null ? null : thresholds.clone(); + mIsEnabled = isEnabled; + } + + public @SignalMeasurementType int getSignalMeasurement() { + return mSignalMeasurement; + } + + public int getHysteresisMs() { + return mHysteresisMs; + } + + public int getHysteresisDb() { + return mHysteresisDb; + } + + public boolean isEnabled() { + return mIsEnabled; + } + + public int[] getThresholds() { + return mThresholds == null ? null : mThresholds.clone(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mSignalMeasurement); + out.writeInt(mHysteresisMs); + out.writeInt(mHysteresisDb); + out.writeIntArray(mThresholds); + out.writeBoolean(mIsEnabled); + } + + private SignalThresholdInfo(Parcel in) { + mSignalMeasurement = in.readInt(); + mHysteresisMs = in.readInt(); + mHysteresisDb = in.readInt(); + mThresholds = in.createIntArray(); + mIsEnabled = in.readBoolean(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (!(o instanceof SignalThresholdInfo)) { + return false; + } + + SignalThresholdInfo other = (SignalThresholdInfo) o; + return mSignalMeasurement == other.mSignalMeasurement + && mHysteresisMs == other.mHysteresisMs + && mHysteresisDb == other.mHysteresisDb + && Arrays.equals(mThresholds, other.mThresholds) + && mIsEnabled == other.mIsEnabled; + } + + @Override + public int hashCode() { + return Objects.hash( + mSignalMeasurement, mHysteresisMs, mHysteresisDb, mThresholds, mIsEnabled); + } + + public static final @NonNull Parcelable.Creator<SignalThresholdInfo> CREATOR = + new Parcelable.Creator<SignalThresholdInfo>() { + @Override + public SignalThresholdInfo createFromParcel(Parcel in) { + return new SignalThresholdInfo(in); + } + + @Override + public SignalThresholdInfo[] newArray(int size) { + return new SignalThresholdInfo[size]; + } + }; + + @Override + public String toString() { + return new StringBuilder("SignalThresholdInfo{") + .append("mSignalMeasurement=").append(mSignalMeasurement) + .append("mHysteresisMs=").append(mSignalMeasurement) + .append("mHysteresisDb=").append(mHysteresisDb) + .append("mThresholds=").append(Arrays.toString(mThresholds)) + .append("mIsEnabled=").append(mIsEnabled) + .append("}").toString(); + } +} diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 9eff809eaf5d..ebb517596b6c 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -89,8 +89,8 @@ public class SubscriptionInfo implements Parcelable { private int mCarrierId; /** - * The source of the name, NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SOURCE or - * NAME_SOURCE_USER_INPUT. + * The source of the name, NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SPN, + * NAME_SOURCE_SIM_PNN, or NAME_SOURCE_USER_INPUT. */ private int mNameSource; @@ -334,7 +334,7 @@ public class SubscriptionInfo implements Parcelable { } /** - * @return the source of the name, eg NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SOURCE or + * @return the source of the name, eg NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SPN or * NAME_SOURCE_USER_INPUT. * @hide */ diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index fbbf75a85a9b..a82ae887224c 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -48,12 +48,12 @@ import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Looper; import android.os.ParcelUuid; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.provider.Telephony.SimInfo; import android.telephony.euicc.EuiccManager; import android.telephony.ims.ImsMmTelManager; import android.util.DisplayMetrics; @@ -63,6 +63,7 @@ import android.util.Pair; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.util.HandlerExecutor; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; @@ -129,7 +130,7 @@ public class SubscriptionManager { /** @hide */ @UnsupportedAppUsage - public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo"); + public static final Uri CONTENT_URI = SimInfo.CONTENT_URI; /** * Generates a content {@link Uri} used to receive updates on simInfo change @@ -400,19 +401,19 @@ public class SubscriptionManager { public static final String NAME_SOURCE = "name_source"; /** - * The name_source is the default + * The name_source is the default, which is from the carrier id. * @hide */ public static final int NAME_SOURCE_DEFAULT_SOURCE = 0; /** - * The name_source is from the SIM + * The name_source is from SIM EF_SPN. * @hide */ - public static final int NAME_SOURCE_SIM_SOURCE = 1; + public static final int NAME_SOURCE_SIM_SPN = 1; /** - * The name_source is from the user + * The name_source is from user input * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) @@ -425,6 +426,24 @@ public class SubscriptionManager { public static final int NAME_SOURCE_CARRIER = 3; /** + * The name_source is from SIM EF_PNN. + * @hide + */ + public static final int NAME_SOURCE_SIM_PNN = 4; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"NAME_SOURCE_"}, + value = { + NAME_SOURCE_DEFAULT_SOURCE, + NAME_SOURCE_SIM_SPN, + NAME_SOURCE_USER_INPUT, + NAME_SOURCE_CARRIER, + NAME_SOURCE_SIM_PNN + }) + public @interface SimDisplayNameSource {} + + /** * TelephonyProvider column name for the color of a SIM. * <P>Type: INTEGER (int)</P> */ @@ -1667,13 +1686,12 @@ public class SubscriptionManager { * Set display name by simInfo index with name source * @param displayName the display name of SIM card * @param subId the unique SubscriptionInfo index in database - * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE, - * 2: NAME_SOURCE_USER_INPUT + * @param nameSource SIM display name source * @return the number of records updated or < 0 if invalid subId * @hide */ @UnsupportedAppUsage - public int setDisplayName(String displayName, int subId, int nameSource) { + public int setDisplayName(String displayName, int subId, @SimDisplayNameSource int nameSource) { if (VDBG) { logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId + " nameSource:" + nameSource); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index e3981f6abf34..97e62dcb31f3 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -716,31 +716,6 @@ public class TelephonyManager { public static final String EXTRA_INCOMING_NUMBER = "incoming_number"; /** - * Broadcast intent action indicating that a precise call state - * (cellular) on the device has changed. - * - * <p> - * The {@link #EXTRA_RINGING_CALL_STATE} extra indicates the ringing call state. - * The {@link #EXTRA_FOREGROUND_CALL_STATE} extra indicates the foreground call state. - * The {@link #EXTRA_BACKGROUND_CALL_STATE} extra indicates the background call state. - * - * <p class="note"> - * Requires the READ_PRECISE_PHONE_STATE permission. - * - * @see #EXTRA_RINGING_CALL_STATE - * @see #EXTRA_FOREGROUND_CALL_STATE - * @see #EXTRA_BACKGROUND_CALL_STATE - * - * <p class="note"> - * Requires the READ_PRECISE_PHONE_STATE permission. - * @deprecated use {@link PhoneStateListener#LISTEN_PRECISE_CALL_STATE} instead - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_PRECISE_CALL_STATE_CHANGED = - "android.intent.action.PRECISE_CALL_STATE"; - - /** * Broadcast intent action indicating that call disconnect cause has changed. * * <p> @@ -762,78 +737,6 @@ public class TelephonyManager { /** * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer - * containing the state of the current ringing call. - * - * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID - * @see PreciseCallState#PRECISE_CALL_STATE_IDLE - * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE - * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING - * @see PreciseCallState#PRECISE_CALL_STATE_DIALING - * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING - * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING - * @see PreciseCallState#PRECISE_CALL_STATE_WAITING - * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED - * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING - * - * <p class="note"> - * Retrieve with - * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}. - * - * @hide - */ - public static final String EXTRA_RINGING_CALL_STATE = "ringing_state"; - - /** - * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and - * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer - * containing the state of the current foreground call. - * - * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID - * @see PreciseCallState#PRECISE_CALL_STATE_IDLE - * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE - * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING - * @see PreciseCallState#PRECISE_CALL_STATE_DIALING - * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING - * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING - * @see PreciseCallState#PRECISE_CALL_STATE_WAITING - * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED - * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING - * - * <p class="note"> - * Retrieve with - * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}. - * - * @hide - */ - public static final String EXTRA_FOREGROUND_CALL_STATE = "foreground_state"; - - /** - * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and - * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer - * containing the state of the current background call. - * - * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID - * @see PreciseCallState#PRECISE_CALL_STATE_IDLE - * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE - * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING - * @see PreciseCallState#PRECISE_CALL_STATE_DIALING - * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING - * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING - * @see PreciseCallState#PRECISE_CALL_STATE_WAITING - * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED - * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING - * - * <p class="note"> - * Retrieve with - * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}. - * - * @hide - */ - public static final String EXTRA_BACKGROUND_CALL_STATE = "background_state"; - - /** - * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and - * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer * containing the disconnect cause. * * @see DisconnectCause diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java index 47c468121484..5adc99e11478 100644 --- a/telephony/java/android/telephony/ims/ImsCallSession.java +++ b/telephony/java/android/telephony/ims/ImsCallSession.java @@ -1173,18 +1173,8 @@ public class ImsCallSession { public void callSessionMergeComplete(IImsCallSession newSession) { if (mListener != null) { if (newSession != null) { - // Check if the active session is the same session that was - // active before the merge request was sent. - ImsCallSession validActiveSession = ImsCallSession.this; - try { - if (!Objects.equals(miSession.getCallId(), newSession.getCallId())) { - // New session created after conference - validActiveSession = new ImsCallSession(newSession); - } - } catch (RemoteException rex) { - Log.e(TAG, "callSessionMergeComplete: exception for getCallId!"); - } - mListener.callSessionMergeComplete(validActiveSession); + // New session created after conference + mListener.callSessionMergeComplete(new ImsCallSession(newSession)); } else { // Session already exists. Hence no need to pass mListener.callSessionMergeComplete(null); diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index 5fd0af564d34..057d22cd7eae 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -161,9 +161,13 @@ public class ImsMmTelManager implements RegistrationManager { public void onCapabilitiesStatusChanged(int config) { if (mLocalCallback == null) return; - Binder.withCleanCallingIdentity(() -> - mExecutor.execute(() -> mLocalCallback.onCapabilitiesStatusChanged( - new MmTelFeature.MmTelCapabilities(config)))); + long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mLocalCallback.onCapabilitiesStatusChanged( + new MmTelFeature.MmTelCapabilities(config))); + } finally { + restoreCallingIdentity(callingIdentity); + } } @Override diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java index 21707b0d7cfd..b37d7c759be3 100644 --- a/telephony/java/android/telephony/ims/ImsRcsManager.java +++ b/telephony/java/android/telephony/ims/ImsRcsManager.java @@ -67,9 +67,13 @@ public class ImsRcsManager implements RegistrationManager { public void onCapabilitiesStatusChanged(int config) { if (mLocalCallback == null) return; - Binder.withCleanCallingIdentity(() -> - mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged( - new RcsFeature.RcsImsCapabilities(config)))); + long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged( + new RcsFeature.RcsImsCapabilities(config))); + } finally { + restoreCallingIdentity(callingIdentity); + } } @Override diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index e16085e30465..e4d63355625d 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -136,17 +136,24 @@ public class ProvisioningManager { @Override public final void onIntConfigChanged(int item, int value) { - Binder.withCleanCallingIdentity(() -> - mExecutor.execute(() -> - mLocalConfigurationCallback.onProvisioningIntChanged(item, value))); + long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> + mLocalConfigurationCallback.onProvisioningIntChanged(item, value)); + } finally { + restoreCallingIdentity(callingIdentity); + } } @Override public final void onStringConfigChanged(int item, String value) { - Binder.withCleanCallingIdentity(() -> - mExecutor.execute(() -> - mLocalConfigurationCallback.onProvisioningStringChanged(item, - value))); + long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> + mLocalConfigurationCallback.onProvisioningStringChanged(item, value)); + } finally { + restoreCallingIdentity(callingIdentity); + } } private void setExecutor(Executor executor) { diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java index b47bcb9b119b..75e3f0a6393d 100644 --- a/telephony/java/android/telephony/ims/RcsUceAdapter.java +++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java @@ -245,15 +245,22 @@ public class RcsUceAdapter { IRcsUceControllerCallback internalCallback = new IRcsUceControllerCallback.Stub() { @Override public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) { - Binder.withCleanCallingIdentity(() -> - executor.execute(() -> - c.onCapabilitiesReceived(contactCapabilities))); + long callingIdentity = Binder.clearCallingIdentity(); + try { + executor.execute(() -> + c.onCapabilitiesReceived(contactCapabilities)); + } finally { + restoreCallingIdentity(callingIdentity); + } } @Override public void onError(int errorCode) { - Binder.withCleanCallingIdentity(() -> - executor.execute(() -> - c.onError(errorCode))); + long callingIdentity = Binder.clearCallingIdentity(); + try { + executor.execute(() -> c.onError(errorCode)); + } finally { + restoreCallingIdentity(callingIdentity); + } } }; diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java index 99bb259602e5..ca081ec1ea51 100644 --- a/telephony/java/android/telephony/ims/RegistrationManager.java +++ b/telephony/java/android/telephony/ims/RegistrationManager.java @@ -110,42 +110,63 @@ public interface RegistrationManager { public void onRegistered(int imsRadioTech) { if (mLocalCallback == null) return; - Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> - mLocalCallback.onRegistered(getAccessType(imsRadioTech)))); + long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> + mLocalCallback.onRegistered(getAccessType(imsRadioTech))); + } finally { + restoreCallingIdentity(callingIdentity); + } } @Override public void onRegistering(int imsRadioTech) { if (mLocalCallback == null) return; - Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> - mLocalCallback.onRegistering(getAccessType(imsRadioTech)))); + long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> + mLocalCallback.onRegistering(getAccessType(imsRadioTech))); + } finally { + restoreCallingIdentity(callingIdentity); + } } @Override public void onDeregistered(ImsReasonInfo info) { if (mLocalCallback == null) return; - Binder.withCleanCallingIdentity(() -> - mExecutor.execute(() -> mLocalCallback.onUnregistered(info))); + long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mLocalCallback.onUnregistered(info)); + } finally { + restoreCallingIdentity(callingIdentity); + } } @Override public void onTechnologyChangeFailed(int imsRadioTech, ImsReasonInfo info) { if (mLocalCallback == null) return; - Binder.withCleanCallingIdentity(() -> - mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed( - getAccessType(imsRadioTech), info))); + long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed( + getAccessType(imsRadioTech), info)); + } finally { + restoreCallingIdentity(callingIdentity); + } } @Override public void onSubscriberAssociatedUriChanged(Uri[] uris) { if (mLocalCallback == null) return; - Binder.withCleanCallingIdentity(() -> - mExecutor.execute(() -> - mLocalCallback.onSubscriberAssociatedUriChanged(uris))); + long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mLocalCallback.onSubscriberAssociatedUriChanged(uris)); + } finally { + restoreCallingIdentity(callingIdentity); + } } private void setExecutor(Executor executor) { diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index e96d082ca953..0eaf8dc2fd51 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -22,7 +22,6 @@ import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; import android.net.Uri; -import android.os.Binder; import android.os.RemoteException; import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.aidl.IImsCapabilityCallback; @@ -33,7 +32,7 @@ import android.telephony.ims.stub.RcsPresenceExchangeImplBase; import android.telephony.ims.stub.RcsSipOptionsImplBase; import android.util.Log; -import com.android.internal.util.FunctionalUtils; +import com.android.internal.telephony.util.TelephonyUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -43,6 +42,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; +import java.util.function.Supplier; /** * Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend @@ -150,13 +150,13 @@ public class RcsFeature extends ImsFeature { // Call the methods with a clean calling identity on the executor and wait indefinitely for // the future to return. - private void executeMethodAsync(FunctionalUtils.ThrowingRunnable r, String errorLogName) + private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException { // call with a clean calling identity on the executor and wait indefinitely for the // future to return. try { CompletableFuture.runAsync( - () -> Binder.withCleanCallingIdentity(r), mExecutor).join(); + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); } catch (CancellationException | CompletionException e) { Log.w(LOG_TAG, "RcsFeatureBinder - " + errorLogName + " exception: " + e.getMessage()); @@ -164,12 +164,12 @@ public class RcsFeature extends ImsFeature { } } - private <T> T executeMethodAsyncForResult(FunctionalUtils.ThrowingSupplier<T> r, + private <T> T executeMethodAsyncForResult(Supplier<T> r, String errorLogName) throws RemoteException { // call with a clean calling identity on the executor and wait indefinitely for the // future to return. CompletableFuture<T> future = CompletableFuture.supplyAsync( - () -> Binder.withCleanCallingIdentity(r), mExecutor); + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); try { return future.get(); } catch (ExecutionException | InterruptedException e) { diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java index 4fc6a19d1f38..cfc803ca3639 100644 --- a/telephony/java/com/android/ims/ImsConfig.java +++ b/telephony/java/com/android/ims/ImsConfig.java @@ -17,7 +17,6 @@ package com.android.ims; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Looper; import android.os.RemoteException; import android.telephony.Rlog; @@ -26,6 +25,8 @@ import android.telephony.ims.ProvisioningManager; import android.telephony.ims.aidl.IImsConfig; import android.telephony.ims.aidl.IImsConfigCallback; +import com.android.internal.telephony.util.HandlerExecutor; + import java.util.concurrent.Executor; /** diff --git a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl index ee09c1c9c62f..76ebc0f3ac2f 100644 --- a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl +++ b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl @@ -30,7 +30,7 @@ interface ICarrierConfigLoader { PersistableBundle getConfigForSubIdWithFeature(int subId, String callingPackage, String callingFeatureId); - void overrideConfig(int subId, in PersistableBundle overrides); + void overrideConfig(int subId, in PersistableBundle overrides, boolean persistent); void notifyConfigChangedForSubId(int subId); diff --git a/telephony/java/com/android/internal/telephony/IccCardConstants.java b/telephony/java/com/android/internal/telephony/IccCardConstants.java index 6ff27b1152c8..25f03c200610 100644 --- a/telephony/java/com/android/internal/telephony/IccCardConstants.java +++ b/telephony/java/com/android/internal/telephony/IccCardConstants.java @@ -15,6 +15,7 @@ */ package com.android.internal.telephony; +import android.content.Intent; import android.telephony.TelephonyManager; import dalvik.annotation.compat.UnsupportedAppUsage; @@ -25,37 +26,38 @@ import dalvik.annotation.compat.UnsupportedAppUsage; public class IccCardConstants { /* The extra data for broadcasting intent INTENT_ICC_STATE_CHANGE */ - public static final String INTENT_KEY_ICC_STATE = "ss"; + public static final String INTENT_KEY_ICC_STATE = Intent.EXTRA_SIM_STATE; /* UNKNOWN means the ICC state is unknown */ - public static final String INTENT_VALUE_ICC_UNKNOWN = "UNKNOWN"; + public static final String INTENT_VALUE_ICC_UNKNOWN = Intent.SIM_STATE_UNKNOWN; /* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */ - public static final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY"; + public static final String INTENT_VALUE_ICC_NOT_READY = Intent.SIM_STATE_NOT_READY; /* ABSENT means ICC is missing */ - public static final String INTENT_VALUE_ICC_ABSENT = "ABSENT"; + public static final String INTENT_VALUE_ICC_ABSENT = Intent.SIM_STATE_ABSENT; /* PRESENT means ICC is present */ - public static final String INTENT_VALUE_ICC_PRESENT = "PRESENT"; + public static final String INTENT_VALUE_ICC_PRESENT = Intent.SIM_STATE_PRESENT; /* CARD_IO_ERROR means for three consecutive times there was SIM IO error */ - static public final String INTENT_VALUE_ICC_CARD_IO_ERROR = "CARD_IO_ERROR"; + static public final String INTENT_VALUE_ICC_CARD_IO_ERROR = Intent.SIM_STATE_CARD_IO_ERROR; /* CARD_RESTRICTED means card is present but not usable due to carrier restrictions */ - static public final String INTENT_VALUE_ICC_CARD_RESTRICTED = "CARD_RESTRICTED"; + static public final String INTENT_VALUE_ICC_CARD_RESTRICTED = Intent.SIM_STATE_CARD_RESTRICTED; /* LOCKED means ICC is locked by pin or by network */ - public static final String INTENT_VALUE_ICC_LOCKED = "LOCKED"; + public static final String INTENT_VALUE_ICC_LOCKED = Intent.SIM_STATE_LOCKED; /* READY means ICC is ready to access */ - public static final String INTENT_VALUE_ICC_READY = "READY"; + public static final String INTENT_VALUE_ICC_READY = Intent.SIM_STATE_READY; /* IMSI means ICC IMSI is ready in property */ - public static final String INTENT_VALUE_ICC_IMSI = "IMSI"; + public static final String INTENT_VALUE_ICC_IMSI = Intent.SIM_STATE_IMSI; /* LOADED means all ICC records, including IMSI, are loaded */ - public static final String INTENT_VALUE_ICC_LOADED = "LOADED"; + public static final String INTENT_VALUE_ICC_LOADED = Intent.SIM_STATE_LOADED; /* The extra data for broadcasting intent INTENT_ICC_STATE_CHANGE */ - public static final String INTENT_KEY_LOCKED_REASON = "reason"; + public static final String INTENT_KEY_LOCKED_REASON = Intent.EXTRA_SIM_LOCKED_REASON; /* PIN means ICC is locked on PIN1 */ - public static final String INTENT_VALUE_LOCKED_ON_PIN = "PIN"; + public static final String INTENT_VALUE_LOCKED_ON_PIN = Intent.SIM_LOCKED_ON_PIN; /* PUK means ICC is locked on PUK1 */ - public static final String INTENT_VALUE_LOCKED_ON_PUK = "PUK"; + public static final String INTENT_VALUE_LOCKED_ON_PUK = Intent.SIM_LOCKED_ON_PUK; /* NETWORK means ICC is locked on NETWORK PERSONALIZATION */ - public static final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK"; + public static final String INTENT_VALUE_LOCKED_NETWORK = Intent.SIM_LOCKED_NETWORK; /* PERM_DISABLED means ICC is permanently disabled due to puk fails */ - public static final String INTENT_VALUE_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED"; + public static final String INTENT_VALUE_ABSENT_ON_PERM_DISABLED = + Intent.SIM_ABSENT_ON_PERM_DISABLED; /** * This is combination of IccCardStatus.CardState and IccCardApplicationStatus.AppState diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index c19ae7b3916a..aad7f3e7bf2a 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -182,10 +182,6 @@ public class PhoneConstants { public static final String SLOT_KEY = "slot"; - /** Fired when a subscriptions phone state changes. */ - public static final String ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED = - "android.intent.action.SUBSCRIPTION_PHONE_STATE"; - // FIXME: This is used to pass a subId via intents, we need to look at its usage, which is // FIXME: extensive, and see if this should be an array of all active subId's or ...? /** diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 22168c54510b..9cbcd7fc6b04 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -489,6 +489,8 @@ public interface RILConstants { int RIL_REQUEST_EMERGENCY_DIAL = 205; int RIL_REQUEST_GET_PHONE_CAPABILITY = 206; int RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG = 207; + int RIL_REQUEST_ENABLE_UICC_APPLICATIONS = 208; + int RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT = 209; /* Responses begin */ int RIL_RESPONSE_ACKNOWLEDGEMENT = 800; @@ -552,4 +554,5 @@ public interface RILConstants { int RIL_UNSOL_ICC_SLOT_STATUS = 1100; int RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG = 1101; int RIL_UNSOL_EMERGENCY_NUMBER_LIST = 1102; + int RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED = 1103; } diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 8b62872b77af..b2c3fc79025b 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -240,25 +240,6 @@ public class TelephonyIntents { */ public static final String ACTION_NETWORK_SET_TIME = "android.intent.action.NETWORK_SET_TIME"; - - /** - * Broadcast Action: The timezone was set by the carrier (typically by the NITZ string). - * This is a sticky broadcast. - * The intent will have the following extra values:</p> - * <ul> - * <li><em>time-zone</em> - The java.util.TimeZone.getID() value identifying the new time - * zone.</li> - * </ul> - * - * <p class="note"> - * Requires the READ_PHONE_STATE permission. - * - * <p class="note">This is a protected intent that can only be sent - * by the system. - */ - public static final String ACTION_NETWORK_SET_TIMEZONE - = "android.intent.action.NETWORK_SET_TIMEZONE"; - /** * <p>Broadcast Action: It indicates the Emergency callback mode blocks datacall/sms * <p class="note">. diff --git a/telephony/java/com/android/internal/telephony/util/HandlerExecutor.java b/telephony/java/com/android/internal/telephony/util/HandlerExecutor.java new file mode 100644 index 000000000000..8a2545772b5b --- /dev/null +++ b/telephony/java/com/android/internal/telephony/util/HandlerExecutor.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.util; + +import android.annotation.NonNull; +import android.os.Handler; + +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; + +/** + * An adapter {@link Executor} that posts all executed tasks onto the given + * {@link Handler}. + * + * @hide + */ +public class HandlerExecutor implements Executor { + private final Handler mHandler; + + public HandlerExecutor(@NonNull Handler handler) { + if (handler == null) { + throw new NullPointerException(); + } + mHandler = handler; + } + + @Override + public void execute(Runnable command) { + if (!mHandler.post(command)) { + throw new RejectedExecutionException(mHandler + " is shutting down"); + } + } +} diff --git a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java index a28d65c9abb6..306b9eeca6e3 100644 --- a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java +++ b/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java @@ -26,6 +26,7 @@ import android.os.RemoteException; import android.os.SystemProperties; import java.io.PrintWriter; +import java.util.function.Supplier; /** * This class provides various util functions @@ -71,4 +72,40 @@ public final class TelephonyUtils { if (resolveInfo.providerInfo != null) return resolveInfo.providerInfo; throw new IllegalStateException("Missing ComponentInfo!"); } + + /** + * Convenience method for running the provided action enclosed in + * {@link Binder#clearCallingIdentity}/{@link Binder#restoreCallingIdentity} + * + * Any exception thrown by the given action will need to be handled by caller. + * + */ + public static void runWithCleanCallingIdentity( + @NonNull Runnable action) { + long callingIdentity = Binder.clearCallingIdentity(); + try { + action.run(); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + + + /** + * Convenience method for running the provided action enclosed in + * {@link Binder#clearCallingIdentity}/{@link Binder#restoreCallingIdentity} and return + * the result. + * + * Any exception thrown by the given action will need to be handled by caller. + * + */ + public static <T> T runWithCleanCallingIdentity( + @NonNull Supplier<T> action) { + long callingIdentity = Binder.clearCallingIdentity(); + try { + return action.get(); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } } diff --git a/test-mock/Android.bp b/test-mock/Android.bp index aa4174ad40f4..616b6b005f89 100644 --- a/test-mock/Android.bp +++ b/test-mock/Android.bp @@ -30,6 +30,7 @@ java_sdk_library { libs: [ "framework-all", "app-compat-annotations", + "unsupportedappusage", ], api_packages: [ diff --git a/tests/ApkVerityTest/Android.bp b/tests/ApkVerityTest/Android.bp index adcbb4287dd0..9bb9983f66a9 100644 --- a/tests/ApkVerityTest/Android.bp +++ b/tests/ApkVerityTest/Android.bp @@ -13,7 +13,7 @@ // limitations under the License. java_test_host { - name: "ApkVerityTests", + name: "ApkVerityTest", srcs: ["src/**/*.java"], libs: ["tradefed", "compatibility-tradefed", "compatibility-host-util"], test_suites: ["general-tests"], diff --git a/tests/ApkVerityTest/AndroidTest.xml b/tests/ApkVerityTest/AndroidTest.xml index 73779cbd1a87..51bcdea21f49 100644 --- a/tests/ApkVerityTest/AndroidTest.xml +++ b/tests/ApkVerityTest/AndroidTest.xml @@ -36,6 +36,6 @@ </target_preparer> <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" > - <option name="jar" value="ApkVerityTests.jar" /> + <option name="jar" value="ApkVerityTest.jar" /> </test> </configuration> diff --git a/tests/ApkVerityTest/TEST_MAPPING b/tests/ApkVerityTest/TEST_MAPPING new file mode 100644 index 000000000000..a6608399d83c --- /dev/null +++ b/tests/ApkVerityTest/TEST_MAPPING @@ -0,0 +1,15 @@ +{ + "presubmit": [ + // nextgen test only runs during postsubmit. + { + "name": "ApkVerityTest", + "keywords": ["nextgen"] + } + ], + "postsubmit": [ + // TODO: move to presubmit once it's confirmed stable. + { + "name": "ApkVerityTest" + } + ] +} diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml index d433df56bc00..d1da47f0f9d8 100644 --- a/tests/FlickerTests/AndroidTest.xml +++ b/tests/FlickerTests/AndroidTest.xml @@ -25,6 +25,6 @@ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> <option name="directory-keys" value="/sdcard/flicker" /> <option name="collect-on-run-ended-only" value="true" /> - <option name="clean-up" value="false" /> + <option name="clean-up" value="true" /> </metrics_collector> </configuration> diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index e30878157a26..ef8facec9752 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -118,7 +118,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // The failed packages should be the same as the registered ones to ensure registration is // done successfully @@ -135,7 +136,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE), - new VersionedPackage(APP_B, VERSION_CODE))); + new VersionedPackage(APP_B, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // The failed packages should be the same as the registered ones to ensure registration is // done successfully @@ -151,7 +153,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION); watchdog.unregisterHealthObserver(observer); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // We should have no failed packages to ensure unregistration is done successfully assertThat(observer.mHealthCheckFailedPackages).isEmpty(); @@ -167,7 +170,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION); watchdog.unregisterHealthObserver(observer2); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // observer1 should receive failed packages as intended. assertThat(observer1.mHealthCheckFailedPackages).containsExactly(APP_A); @@ -183,7 +187,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION); moveTimeForwardAndDispatch(SHORT_DURATION); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // We should have no failed packages for the fatal failure is raised after expiration assertThat(observer.mHealthCheckFailedPackages).isEmpty(); @@ -199,7 +204,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), LONG_DURATION); moveTimeForwardAndDispatch(SHORT_DURATION); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // We should have no failed packages for the fatal failure is raised after expiration assertThat(observer1.mHealthCheckFailedPackages).isEmpty(); @@ -226,7 +232,8 @@ public class PackageWatchdogTest { moveTimeForwardAndDispatch((SHORT_DURATION / 2) + 1); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify that we receive failed packages as expected for APP_A not expired assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A); @@ -252,7 +259,8 @@ public class PackageWatchdogTest { watchdog2.registerHealthObserver(observer2); raiseFatalFailureAndDispatch(watchdog2, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE), - new VersionedPackage(APP_B, VERSION_CODE))); + new VersionedPackage(APP_B, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // We should receive failed packages as expected to ensure observers are persisted and // resumed correctly @@ -274,7 +282,8 @@ public class PackageWatchdogTest { // Then fail APP_A below the threshold for (int i = 0; i < watchdog.getTriggerFailureCount() - 1; i++) { - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } // Run handler so package failures are dispatched to observers @@ -301,7 +310,8 @@ public class PackageWatchdogTest { // Then fail APP_C (not observed) above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify that observers are not notified assertThat(observer1.mHealthCheckFailedPackages).isEmpty(); @@ -331,7 +341,8 @@ public class PackageWatchdogTest { // Then fail APP_A (different version) above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, differentVersionCode))); + Arrays.asList(new VersionedPackage(APP_A, differentVersionCode)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify that observers are not notified assertThat(observer.mHealthCheckFailedPackages).isEmpty(); @@ -368,7 +379,8 @@ public class PackageWatchdogTest { Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE), new VersionedPackage(APP_B, VERSION_CODE), new VersionedPackage(APP_C, VERSION_CODE), - new VersionedPackage(APP_D, VERSION_CODE))); + new VersionedPackage(APP_D, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify least impact observers are notifed of package failures List<String> observerNonePackages = observerNone.mMitigatedPackages; @@ -411,7 +423,8 @@ public class PackageWatchdogTest { // Then fail APP_A above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify only observerFirst is notifed assertThat(observerFirst.mMitigatedPackages).containsExactly(APP_A); @@ -424,7 +437,8 @@ public class PackageWatchdogTest { // Then fail APP_A again above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify only observerSecond is notifed cos it has least impact assertThat(observerSecond.mMitigatedPackages).containsExactly(APP_A); @@ -437,7 +451,8 @@ public class PackageWatchdogTest { // Then fail APP_A again above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify only observerFirst is notifed cos it has the only action assertThat(observerFirst.mMitigatedPackages).containsExactly(APP_A); @@ -450,7 +465,8 @@ public class PackageWatchdogTest { // Then fail APP_A again above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify no observer is notified cos no actions left assertThat(observerFirst.mMitigatedPackages).isEmpty(); @@ -474,7 +490,8 @@ public class PackageWatchdogTest { // Then fail APP_A above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify only one observer is notifed assertThat(observer1.mMitigatedPackages).containsExactly(APP_A); @@ -746,13 +763,15 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION); // Fail APP_A below the threshold which should not trigger package failures for (int i = 0; i < PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT - 1; i++) { - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } mTestLooper.dispatchAll(); assertThat(observer.mHealthCheckFailedPackages).isEmpty(); // One more to trigger the package failure - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A); } @@ -773,20 +792,24 @@ public class PackageWatchdogTest { TestObserver observer = new TestObserver(OBSERVER_NAME_1); watchdog.startObservingHealth(observer, Arrays.asList(APP_A, APP_B), Long.MAX_VALUE); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS + 1); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); // We shouldn't receive APP_A since the interval of 2 failures is greater than // DEFAULT_TRIGGER_FAILURE_DURATION_MS. assertThat(observer.mHealthCheckFailedPackages).isEmpty(); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS - 1); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); // We should receive APP_B since the interval of 2 failures is less than @@ -809,7 +832,8 @@ public class PackageWatchdogTest { // small timeouts. moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS - 100); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // We should receive APP_A since the observer hasn't expired assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A); @@ -827,7 +851,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), -1); moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS + 1); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // We should receive nothing since the observer has expired assertThat(observer.mHealthCheckFailedPackages).isEmpty(); @@ -850,22 +875,59 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), Long.MAX_VALUE); // Raise 2 failures at t=0 and t=900 respectively - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); moveTimeForwardAndDispatch(900); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); // Raise 2 failures at t=1100 moveTimeForwardAndDispatch(200); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); // We should receive APP_A since there are 3 failures within 1000ms window assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A); } + /** Test that observers execute correctly for different failure reasons */ + @Test + public void testFailureReasons() { + PackageWatchdog watchdog = createWatchdog(); + TestObserver observer1 = new TestObserver(OBSERVER_NAME_1); + TestObserver observer2 = new TestObserver(OBSERVER_NAME_2); + TestObserver observer3 = new TestObserver(OBSERVER_NAME_3); + TestObserver observer4 = new TestObserver(OBSERVER_NAME_4); + + watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.startObservingHealth(observer2, Arrays.asList(APP_B), SHORT_DURATION); + watchdog.startObservingHealth(observer3, Arrays.asList(APP_C), SHORT_DURATION); + watchdog.startObservingHealth(observer4, Arrays.asList(APP_D), SHORT_DURATION); + + raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, + VERSION_CODE)), PackageWatchdog.FAILURE_REASON_NATIVE_CRASH); + raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_B, + VERSION_CODE)), PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK); + raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_C, + VERSION_CODE)), PackageWatchdog.FAILURE_REASON_APP_CRASH); + raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_D, + VERSION_CODE)), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING); + + assertThat(observer1.getLastFailureReason()).isEqualTo( + PackageWatchdog.FAILURE_REASON_NATIVE_CRASH); + assertThat(observer2.getLastFailureReason()).isEqualTo( + PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK); + assertThat(observer3.getLastFailureReason()).isEqualTo( + PackageWatchdog.FAILURE_REASON_APP_CRASH); + assertThat(observer4.getLastFailureReason()).isEqualTo( + PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING); + } + private void adoptShellPermissions(String... permissions) { InstrumentationRegistry .getInstrumentation() @@ -900,9 +962,9 @@ public class PackageWatchdogTest { /** Trigger package failures above the threshold. */ private void raiseFatalFailureAndDispatch(PackageWatchdog watchdog, - List<VersionedPackage> packages) { + List<VersionedPackage> packages, int failureReason) { for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { - watchdog.onPackageFailure(packages); + watchdog.onPackageFailure(packages, failureReason); } mTestLooper.dispatchAll(); } @@ -936,6 +998,7 @@ public class PackageWatchdogTest { private static class TestObserver implements PackageHealthObserver { private final String mName; private int mImpact; + private int mLastFailureReason; final List<String> mHealthCheckFailedPackages = new ArrayList<>(); final List<String> mMitigatedPackages = new ArrayList<>(); @@ -954,14 +1017,19 @@ public class PackageWatchdogTest { return mImpact; } - public boolean execute(VersionedPackage versionedPackage) { + public boolean execute(VersionedPackage versionedPackage, int failureReason) { mMitigatedPackages.add(versionedPackage.getPackageName()); + mLastFailureReason = failureReason; return true; } public String getName() { return mName; } + + public int getLastFailureReason() { + return mLastFailureReason; + } } private static class TestController extends ExplicitHealthCheckController { diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java index 3be7a4a0261d..7b289d8a7858 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java @@ -22,18 +22,14 @@ import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoFo import static com.google.common.truth.Truth.assertThat; import android.Manifest; -import android.annotation.Nullable; import android.content.ComponentName; -import android.content.Context; import android.content.Intent; -import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; import android.os.ParcelFileDescriptor; import android.provider.DeviceConfig; -import android.text.TextUtils; import androidx.test.platform.app.InstrumentationRegistry; @@ -44,7 +40,6 @@ import com.android.cts.install.lib.TestApp; import com.android.cts.install.lib.Uninstall; import com.android.cts.rollback.lib.Rollback; import com.android.cts.rollback.lib.RollbackUtils; -import com.android.internal.R; import libcore.io.IoUtils; @@ -75,7 +70,6 @@ public class StagedRollbackTest { private static final String PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS = "watchdog_request_timeout_millis"; - private static final String MODULE_META_DATA_PACKAGE = getModuleMetadataPackageName(); private static final TestApp NETWORK_STACK = new TestApp("NetworkStack", getNetworkStackPackageName(), -1, false, findNetworkStackApk()); @@ -186,21 +180,15 @@ public class StagedRollbackTest { } /** - * Stage install ModuleMetadata package to simulate a Mainline module update. + * Stage install an apk with rollback that will be later triggered by unattributable crash. */ @Test public void testNativeWatchdogTriggersRollback_Phase1() throws Exception { - resetModuleMetadataPackage(); - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - PackageInfo metadataPackageInfo = context.getPackageManager().getPackageInfo( - MODULE_META_DATA_PACKAGE, 0); - String metadataApkPath = metadataPackageInfo.applicationInfo.sourceDir; - assertThat(metadataApkPath).isNotNull(); - assertThat(metadataApkPath).isNotEqualTo(""); - - runShellCommand("pm install " - + "-r --enable-rollback --staged --wait " - + metadataApkPath); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); + + Install.single(TestApp.A2).setEnableRollback().setStaged().commit(); } /** @@ -208,9 +196,10 @@ public class StagedRollbackTest { */ @Test public void testNativeWatchdogTriggersRollback_Phase2() throws Exception { + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); RollbackManager rm = RollbackUtils.getRollbackManager(); assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), - MODULE_META_DATA_PACKAGE)).isNotNull(); + TestApp.A)).isNotNull(); } /** @@ -218,9 +207,10 @@ public class StagedRollbackTest { */ @Test public void testNativeWatchdogTriggersRollback_Phase3() throws Exception { + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); RollbackManager rm = RollbackUtils.getRollbackManager(); assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(), - MODULE_META_DATA_PACKAGE)).isNotNull(); + TestApp.A)).isNotNull(); } @Test @@ -351,26 +341,6 @@ public class StagedRollbackTest { getNetworkStackPackageName())).isNull(); } - @Nullable - private static String getModuleMetadataPackageName() { - String packageName = InstrumentationRegistry.getInstrumentation().getContext() - .getResources().getString(R.string.config_defaultModuleMetadataProvider); - if (TextUtils.isEmpty(packageName)) { - return null; - } - return packageName; - } - - private void resetModuleMetadataPackage() { - RollbackManager rm = RollbackUtils.getRollbackManager(); - - assertThat(MODULE_META_DATA_PACKAGE).isNotNull(); - rm.expireRollbackForPackage(MODULE_META_DATA_PACKAGE); - - assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), - MODULE_META_DATA_PACKAGE)).isNull(); - } - private static void runShellCommand(String cmd) { ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation() .executeShellCommand(cmd); diff --git a/tests/utils/testutils/Android.bp b/tests/utils/testutils/Android.bp index f71be7b0b7d3..e13f906cdccd 100644 --- a/tests/utils/testutils/Android.bp +++ b/tests/utils/testutils/Android.bp @@ -17,11 +17,24 @@ java_library { name: "frameworks-base-testutils", - srcs: ["java/**/*.java"], + static_libs: [ + "frameworks-base-testutils-minus-mockito", + "mockito-target-minus-junit4", + ] +} + +java_library { + name: "frameworks-base-testutils-minus-mockito", + + srcs: [ + "java/**/*.java", + "java/**/*.kt", + ], static_libs: [ "junit", "hamcrest-library", + "truth-prebuilt", ], libs: [ diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java b/tests/utils/testutils/java/test/package-info.java index 57afcb0e1a0d..c34d7b21ab84 100644 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java +++ b/tests/utils/testutils/java/test/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,13 +12,10 @@ * 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.frameworks.coretests; - -import android.app.Activity; - -public class FirstChildTestActivity extends Activity { - -} +/** + * This package separated from android. because placing classes under android.'s .test/.util + * may be confused with tests for that actual android subpackage. + **/ +package test; diff --git a/tests/utils/testutils/java/test/util/MockitoUtils.kt b/tests/utils/testutils/java/test/util/MockitoUtils.kt new file mode 100644 index 000000000000..5151abe54108 --- /dev/null +++ b/tests/utils/testutils/java/test/util/MockitoUtils.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test.util + +import org.mockito.Answers +import org.mockito.Mockito +import org.mockito.invocation.InvocationOnMock +import org.mockito.stubbing.Answer +import org.mockito.stubbing.Stubber + +object MockitoUtils { + val ANSWER_THROWS = Answer<Any?> { + when (val name = it.method.name) { + "toString" -> return@Answer Answers.CALLS_REAL_METHODS.answer(it) + else -> { + val arguments = it.arguments + ?.takeUnless { it.isEmpty() } + ?.joinToString() + ?.let { + "with $it" + } + .orEmpty() + + throw UnsupportedOperationException("${it.mock::class.java.simpleName}#$name " + + "$arguments should not be called") + } + } + } +} + +inline fun <reified T> mock(block: T.() -> Unit = {}) = Mockito.mock(T::class.java).apply(block) + +fun <Type> Stubber.whenever(mock: Type) = Mockito.`when`(mock) +fun <Type : Any?> whenever(mock: Type) = Mockito.`when`(mock) + +@Suppress("UNCHECKED_CAST") +fun <Type : Any?> whenever(mock: Type, block: InvocationOnMock.() -> Any?) = + Mockito.`when`(mock).thenAnswer { block(it) } + +fun whenever(mock: Unit) = Mockito.`when`(mock).thenAnswer { } + +inline fun <reified T> mockThrowOnUnmocked(block: T.() -> Unit): T { + val swappingAnswer = object : Answer<Any?> { + var delegate: Answer<*> = Answers.RETURNS_DEFAULTS + + override fun answer(invocation: InvocationOnMock?): Any? { + return delegate.answer(invocation) + } + } + + return Mockito.mock(T::class.java, swappingAnswer).apply(block) + .also { + // To allow when() usage inside block, only swap to throwing afterwards + swappingAnswer.delegate = MockitoUtils.ANSWER_THROWS + } +} diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp index 6c3bcf039be1..bb541fe2490b 100644 --- a/tools/aapt2/java/JavaClassGenerator.cpp +++ b/tools/aapt2/java/JavaClassGenerator.cpp @@ -304,9 +304,11 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res auto documentation_remove_iter = std::remove_if(documentation_attrs.begin(), documentation_attrs.end(), [&](StyleableAttr entry) -> bool { - StringPiece attr_comment_line = entry.symbol.value().attribute->GetComment(); - return SkipSymbol(entry.symbol) || attr_comment_line.contains("@removed") - || attr_comment_line.contains("@hide"); + if (SkipSymbol(entry.symbol)) { + return true; + } + const StringPiece attr_comment_line = entry.symbol.value().attribute->GetComment(); + return attr_comment_line.contains("@removed") || attr_comment_line.contains("@hide"); }); documentation_attrs.erase(documentation_remove_iter, documentation_attrs.end()); diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp index 4899fbd3b669..712b48edbc1b 100644 --- a/tools/stats_log_api_gen/java_writer.cpp +++ b/tools/stats_log_api_gen/java_writer.cpp @@ -83,7 +83,7 @@ static int write_java_methods( // Print method body. string indent(""); if (DEFAULT_MODULE_NAME != moduleName) { - fprintf(out, " if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n"); + fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {\n"); indent = " "; } @@ -116,16 +116,19 @@ static int write_java_methods( fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(), argIndex); break; case JAVA_TYPE_BYTE_ARRAY: - fprintf(out, "%s builder.writeByteArray(arg%d);\n", - indent.c_str(), argIndex); + fprintf(out, "%s builder.writeByteArray(null == arg%d ? new byte[0] : arg%d);\n", + indent.c_str(), argIndex, argIndex); break; case JAVA_TYPE_ATTRIBUTION_CHAIN: { const char* uidName = attributionDecl.fields.front().name.c_str(); const char* tagName = attributionDecl.fields.back().name.c_str(); - fprintf(out, "%s builder.writeAttributionChain(%s, %s);\n", - indent.c_str(), uidName, tagName); + fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str()); + fprintf(out, "%s null == %s ? new int[0] : %s,\n", + indent.c_str(), uidName, uidName); + fprintf(out, "%s null == %s ? new String[0] : %s);\n", + indent.c_str(), tagName, tagName); break; } case JAVA_TYPE_KEY_VALUE_PAIR: @@ -186,6 +189,7 @@ static int write_java_methods( } fprintf(out, "\n"); + fprintf(out, "%s builder.usePooledBuffer();\n", indent.c_str()); fprintf(out, "%s StatsLog.write(builder.build());\n", indent.c_str()); // Add support for writing using Q schema if this is not the default module. diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index fccbcf7c101f..b52880e29e30 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -44,7 +44,6 @@ import android.net.wifi.WifiNetworkSuggestion; import android.os.Messenger; import android.os.ResultReceiver; import android.os.WorkSource; -import android.os.connectivity.WifiActivityEnergyInfo; /** * Interface that allows controlling and querying Wi-Fi connectivity. @@ -55,8 +54,6 @@ interface IWifiManager { long getSupportedFeatures(); - WifiActivityEnergyInfo reportActivityInfo(); - oneway void getWifiActivityEnergyInfoAsync(in IOnWifiActivityEnergyInfoListener listener); ParceledListSlice getConfiguredNetworks(String packageName, String featureId); diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java index 449f95e8a161..66b0590511fc 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -22,7 +22,6 @@ import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; -import android.security.Credentials; import android.text.TextUtils; import android.util.Log; @@ -93,10 +92,26 @@ public class WifiEnterpriseConfig implements Parcelable { */ public static final String ENGINE_DISABLE = "0"; + /** + * Key prefix for CA certificates. + * Note: copied from {@link android.security.Credentials#CA_CERTIFICATE} since it is @hide. + */ + private static final String CA_CERTIFICATE = "CACERT_"; + /** + * Key prefix for user certificates. + * Note: copied from {@link android.security.Credentials#USER_CERTIFICATE} since it is @hide. + */ + private static final String USER_CERTIFICATE = "USRCERT_"; + /** + * Key prefix for user private and secret keys. + * Note: copied from {@link android.security.Credentials#USER_PRIVATE_KEY} since it is @hide. + */ + private static final String USER_PRIVATE_KEY = "USRPKEY_"; + /** @hide */ - public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE; + public static final String CA_CERT_PREFIX = KEYSTORE_URI + CA_CERTIFICATE; /** @hide */ - public static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + Credentials.USER_CERTIFICATE; + public static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + USER_CERTIFICATE; /** @hide */ public static final String CLIENT_CERT_KEY = "client_cert"; /** @hide */ @@ -659,7 +674,7 @@ public class WifiEnterpriseConfig implements Parcelable { if (i > 0) { sb.append(CA_CERT_ALIAS_DELIMITER); } - sb.append(encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + aliases[i])); + sb.append(encodeCaCertificateAlias(CA_CERTIFICATE + aliases[i])); } setFieldValue(CA_CERT_KEY, sb.toString(), KEYSTORES_URI); } @@ -693,8 +708,8 @@ public class WifiEnterpriseConfig implements Parcelable { String[] aliases = TextUtils.split(values, CA_CERT_ALIAS_DELIMITER); for (int i = 0; i < aliases.length; i++) { aliases[i] = decodeCaCertificateAlias(aliases[i]); - if (aliases[i].startsWith(Credentials.CA_CERTIFICATE)) { - aliases[i] = aliases[i].substring(Credentials.CA_CERTIFICATE.length()); + if (aliases[i].startsWith(CA_CERTIFICATE)) { + aliases[i] = aliases[i].substring(CA_CERTIFICATE.length()); } } return aliases.length != 0 ? aliases : null; @@ -832,7 +847,7 @@ public class WifiEnterpriseConfig implements Parcelable { @SystemApi public void setClientCertificateAlias(@Nullable String alias) { setFieldValue(CLIENT_CERT_KEY, alias, CLIENT_CERT_PREFIX); - setFieldValue(PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY); + setFieldValue(PRIVATE_KEY_ID_KEY, alias, USER_PRIVATE_KEY); // Also, set engine parameters if (TextUtils.isEmpty(alias)) { setFieldValue(ENGINE_KEY, ENGINE_DISABLE); diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index f3f873b4ead8..f728491d33cd 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -21,7 +21,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.net.NetworkInfo.DetailedState; -import android.net.NetworkUtils; +import android.net.shared.Inet4AddressUtils; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -708,7 +708,7 @@ public class WifiInfo implements Parcelable { public int getIpAddress() { int result = 0; if (mIpAddress instanceof Inet4Address) { - result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress); + result = Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) mIpAddress); } return result; } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 0108d5aa936c..50d62a0b627e 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1069,7 +1069,7 @@ public class WifiManager { * @deprecated This API is non-functional and will have no impact. */ @Deprecated - public static final int WIFI_MODE_FULL = WifiProtoEnums.WIFI_MODE_FULL; // 1 + public static final int WIFI_MODE_FULL = 1; /** * In this Wi-Fi lock mode, Wi-Fi will be kept active, @@ -1083,7 +1083,7 @@ public class WifiManager { * @deprecated This API is non-functional and will have no impact. */ @Deprecated - public static final int WIFI_MODE_SCAN_ONLY = WifiProtoEnums.WIFI_MODE_SCAN_ONLY; // 2 + public static final int WIFI_MODE_SCAN_ONLY = 2; /** * In this Wi-Fi lock mode, Wi-Fi will not go to power save. @@ -1102,7 +1102,7 @@ public class WifiManager { * When there is no support from the hardware, the {@link #WIFI_MODE_FULL_HIGH_PERF} * lock will have no impact. */ - public static final int WIFI_MODE_FULL_HIGH_PERF = WifiProtoEnums.WIFI_MODE_FULL_HIGH_PERF; // 3 + public static final int WIFI_MODE_FULL_HIGH_PERF = 3; /** * In this Wi-Fi lock mode, Wi-Fi will operate with a priority to achieve low latency. @@ -1132,8 +1132,8 @@ public class WifiManager { * lock will be effective when app is running in foreground and screen is on, * while the {@link #WIFI_MODE_FULL_HIGH_PERF} lock will take effect otherwise. */ - public static final int WIFI_MODE_FULL_LOW_LATENCY = - WifiProtoEnums.WIFI_MODE_FULL_LOW_LATENCY; // 4 + public static final int WIFI_MODE_FULL_LOW_LATENCY = 4; + /** Anything worse than or equal to this will show 0 bars. */ @UnsupportedAppUsage @@ -2379,25 +2379,6 @@ public class WifiManager { } /** - * Return the record of {@link WifiActivityEnergyInfo} object that - * has the activity and energy info. This can be used to ascertain what - * the controller has been up to, since the last sample. - * - * @return a record with {@link WifiActivityEnergyInfo} or null if - * report is unavailable or unsupported - * @hide - */ - public WifiActivityEnergyInfo getControllerActivityEnergyInfo() { - try { - synchronized(this) { - return mService.reportActivityInfo(); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}. * diff --git a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java index 24aa23aec7ae..04d2e1a8b5dd 100644 --- a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java +++ b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java @@ -23,7 +23,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.net.MacAddress; import android.net.MatchAllNetworkSpecifier; -import android.net.NetworkAgent; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.os.Parcel; @@ -120,7 +119,7 @@ public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements /** * Match {@link WifiNetworkSpecifier} in app's {@link NetworkRequest} with the - * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link NetworkAgent}. + * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link android.net.NetworkAgent}. */ public boolean satisfiesNetworkSpecifier(@NonNull WifiNetworkSpecifier ns) { // None of these should be null by construction. diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java index e78104d3da38..9fd29ae8d14a 100644 --- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java +++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java @@ -23,12 +23,10 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.app.ActivityThread; import android.net.MacAddress; import android.net.wifi.hotspot2.PasspointConfiguration; import android.os.Parcel; import android.os.Parcelable; -import android.os.Process; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -46,7 +44,6 @@ import java.util.Objects; * {@link WifiManager#addNetworkSuggestions(List)}. */ public final class WifiNetworkSuggestion implements Parcelable { - /** * Builder used to create {@link WifiNetworkSuggestion} objects. */ @@ -563,9 +560,7 @@ public final class WifiNetworkSuggestion implements Parcelable { mPasspointConfiguration, mIsAppInteractionRequired, mIsUserInteractionRequired, - mIsUserAllowed, - Process.myUid(), - ActivityThread.currentApplication().getApplicationContext().getOpPackageName()); + mIsUserAllowed); } } @@ -592,19 +587,6 @@ public final class WifiNetworkSuggestion implements Parcelable { * @hide */ public final boolean isUserInteractionRequired; - - /** - * The UID of the process initializing this network suggestion. - * @hide - */ - public final int suggestorUid; - - /** - * The package name of the process initializing this network suggestion. - * @hide - */ - public final String suggestorPackageName; - /** * Whether app share credential with the user, allow user use provided credential to * connect network manually. @@ -619,8 +601,6 @@ public final class WifiNetworkSuggestion implements Parcelable { this.isAppInteractionRequired = false; this.isUserInteractionRequired = false; this.isUserAllowedToManuallyConnect = true; - this.suggestorUid = -1; - this.suggestorPackageName = null; } /** @hide */ @@ -628,18 +608,14 @@ public final class WifiNetworkSuggestion implements Parcelable { @Nullable PasspointConfiguration passpointConfiguration, boolean isAppInteractionRequired, boolean isUserInteractionRequired, - boolean isUserAllowedToManuallyConnect, - int suggestorUid, @NonNull String suggestorPackageName) { + boolean isUserAllowedToManuallyConnect) { checkNotNull(networkConfiguration); - checkNotNull(suggestorPackageName); this.wifiConfiguration = networkConfiguration; this.passpointConfiguration = passpointConfiguration; this.isAppInteractionRequired = isAppInteractionRequired; this.isUserInteractionRequired = isUserInteractionRequired; this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect; - this.suggestorUid = suggestorUid; - this.suggestorPackageName = suggestorPackageName; } public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR = @@ -651,9 +627,7 @@ public final class WifiNetworkSuggestion implements Parcelable { in.readParcelable(null), // PasspointConfiguration in.readBoolean(), // isAppInteractionRequired in.readBoolean(), // isUserInteractionRequired - in.readBoolean(), // isSharedCredentialWithUser - in.readInt(), // suggestorUid - in.readString() // suggestorPackageName + in.readBoolean() // isSharedCredentialWithUser ); } @@ -675,15 +649,12 @@ public final class WifiNetworkSuggestion implements Parcelable { dest.writeBoolean(isAppInteractionRequired); dest.writeBoolean(isUserInteractionRequired); dest.writeBoolean(isUserAllowedToManuallyConnect); - dest.writeInt(suggestorUid); - dest.writeString(suggestorPackageName); } @Override public int hashCode() { return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.BSSID, - wifiConfiguration.allowedKeyManagement, wifiConfiguration.FQDN, - suggestorUid, suggestorPackageName); + wifiConfiguration.allowedKeyManagement, wifiConfiguration.FQDN); } /** @@ -706,23 +677,19 @@ public final class WifiNetworkSuggestion implements Parcelable { && TextUtils.equals(this.wifiConfiguration.BSSID, lhs.wifiConfiguration.BSSID) && Objects.equals(this.wifiConfiguration.allowedKeyManagement, lhs.wifiConfiguration.allowedKeyManagement) - && TextUtils.equals(this.wifiConfiguration.FQDN, lhs.wifiConfiguration.FQDN) - && this.suggestorUid == lhs.suggestorUid - && TextUtils.equals(this.suggestorPackageName, lhs.suggestorPackageName); + && TextUtils.equals(this.wifiConfiguration.FQDN, lhs.wifiConfiguration.FQDN); } @Override public String toString() { - StringBuilder sb = new StringBuilder("WifiNetworkSuggestion [") - .append(", SSID=").append(wifiConfiguration.SSID) + StringBuilder sb = new StringBuilder("WifiNetworkSuggestion[ ") + .append("SSID=").append(wifiConfiguration.SSID) .append(", BSSID=").append(wifiConfiguration.BSSID) .append(", FQDN=").append(wifiConfiguration.FQDN) .append(", isAppInteractionRequired=").append(isAppInteractionRequired) .append(", isUserInteractionRequired=").append(isUserInteractionRequired) .append(", isUserAllowedToManuallyConnect=").append(isUserAllowedToManuallyConnect) - .append(", suggestorUid=").append(suggestorUid) - .append(", suggestorPackageName=").append(suggestorPackageName) - .append("]"); + .append(" ]"); return sb.toString(); } } diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java index b07d8edde3d4..61ab92c9416f 100644 --- a/wifi/java/android/net/wifi/aware/ConfigRequest.java +++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java @@ -47,6 +47,7 @@ public final class ConfigRequest implements Parcelable { */ public static final int NAN_BAND_24GHZ = 0; public static final int NAN_BAND_5GHZ = 1; + public static final int NAN_BAND_6GHZ = 2; /** * Magic values for Discovery Window (DW) interval configuration @@ -60,6 +61,11 @@ public final class ConfigRequest implements Parcelable { public final boolean mSupport5gBand; /** + * Indicates whether 6G band support is requested. + */ + public final boolean mSupport6gBand; + + /** * Specifies the desired master preference. */ public final int mMasterPreference; @@ -81,9 +87,10 @@ public final class ConfigRequest implements Parcelable { */ public final int mDiscoveryWindowInterval[]; - private ConfigRequest(boolean support5gBand, int masterPreference, int clusterLow, - int clusterHigh, int discoveryWindowInterval[]) { + private ConfigRequest(boolean support5gBand, boolean support6gBand, int masterPreference, + int clusterLow, int clusterHigh, int[] discoveryWindowInterval) { mSupport5gBand = support5gBand; + mSupport6gBand = support6gBand; mMasterPreference = masterPreference; mClusterLow = clusterLow; mClusterHigh = clusterHigh; @@ -92,10 +99,12 @@ public final class ConfigRequest implements Parcelable { @Override public String toString() { - return "ConfigRequest [mSupport5gBand=" + mSupport5gBand + ", mMasterPreference=" - + mMasterPreference + ", mClusterLow=" + mClusterLow + ", mClusterHigh=" - + mClusterHigh + ", mDiscoveryWindowInterval=" - + Arrays.toString(mDiscoveryWindowInterval) + "]"; + return "ConfigRequest [mSupport5gBand=" + mSupport5gBand + + ", mSupport6gBand=" + mSupport6gBand + + ", mMasterPreference=" + mMasterPreference + + ", mClusterLow=" + mClusterLow + + ", mClusterHigh=" + mClusterHigh + + ", mDiscoveryWindowInterval=" + Arrays.toString(mDiscoveryWindowInterval) + "]"; } @Override @@ -106,6 +115,7 @@ public final class ConfigRequest implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mSupport5gBand ? 1 : 0); + dest.writeInt(mSupport6gBand ? 1 : 0); dest.writeInt(mMasterPreference); dest.writeInt(mClusterLow); dest.writeInt(mClusterHigh); @@ -121,13 +131,14 @@ public final class ConfigRequest implements Parcelable { @Override public ConfigRequest createFromParcel(Parcel in) { boolean support5gBand = in.readInt() != 0; + boolean support6gBand = in.readInt() != 0; int masterPreference = in.readInt(); int clusterLow = in.readInt(); int clusterHigh = in.readInt(); int discoveryWindowInterval[] = in.createIntArray(); - return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh, - discoveryWindowInterval); + return new ConfigRequest(support5gBand, support6gBand, masterPreference, clusterLow, + clusterHigh, discoveryWindowInterval); } }; @@ -143,7 +154,9 @@ public final class ConfigRequest implements Parcelable { ConfigRequest lhs = (ConfigRequest) o; - return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference + return mSupport5gBand == lhs.mSupport5gBand + && mSupport6gBand == lhs.mSupport6gBand + && mMasterPreference == lhs.mMasterPreference && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh && Arrays.equals(mDiscoveryWindowInterval, lhs.mDiscoveryWindowInterval); } @@ -153,6 +166,7 @@ public final class ConfigRequest implements Parcelable { int result = 17; result = 31 * result + (mSupport5gBand ? 1 : 0); + result = 31 * result + (mSupport6gBand ? 1 : 0); result = 31 * result + mMasterPreference; result = 31 * result + mClusterLow; result = 31 * result + mClusterHigh; @@ -190,9 +204,9 @@ public final class ConfigRequest implements Parcelable { throw new IllegalArgumentException( "Invalid argument combination - must have Cluster Low <= Cluster High"); } - if (mDiscoveryWindowInterval.length != 2) { + if (mDiscoveryWindowInterval.length != 3) { throw new IllegalArgumentException( - "Invalid discovery window interval: must have 2 elements (2.4 & 5"); + "Invalid discovery window interval: must have 3 elements (2.4 & 5 & 6"); } if (mDiscoveryWindowInterval[NAN_BAND_24GHZ] != DW_INTERVAL_NOT_INIT && (mDiscoveryWindowInterval[NAN_BAND_24GHZ] < 1 // valid for 2.4GHz: [1-5] @@ -206,7 +220,12 @@ public final class ConfigRequest implements Parcelable { throw new IllegalArgumentException( "Invalid discovery window interval for 5GHz: valid is UNSET or [0,5]"); } - + if (mDiscoveryWindowInterval[NAN_BAND_6GHZ] != DW_INTERVAL_NOT_INIT + && (mDiscoveryWindowInterval[NAN_BAND_6GHZ] < 0 // valid for 6GHz: [0-5] + || mDiscoveryWindowInterval[NAN_BAND_6GHZ] > 5)) { + throw new IllegalArgumentException( + "Invalid discovery window interval for 6GHz: valid is UNSET or [0,5]"); + } } /** @@ -214,10 +233,12 @@ public final class ConfigRequest implements Parcelable { */ public static final class Builder { private boolean mSupport5gBand = true; + private boolean mSupport6gBand = false; private int mMasterPreference = 0; private int mClusterLow = CLUSTER_ID_MIN; private int mClusterHigh = CLUSTER_ID_MAX; - private int mDiscoveryWindowInterval[] = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT}; + private int[] mDiscoveryWindowInterval = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT, + DW_INTERVAL_NOT_INIT}; /** * Specify whether 5G band support is required in this request. Disabled by default. @@ -233,6 +254,19 @@ public final class ConfigRequest implements Parcelable { } /** + * Specify whether 6G band support is required in this request. Disabled by default. + * + * @param support6gBand Support for 6G band is required. + * + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setSupport6gBand(boolean support6gBand) { + mSupport6gBand = support6gBand; + return this; + } + + /** * Specify the Master Preference requested. The permitted range is 0 (the default) to * 255 with 1 and 255 excluded (reserved). * @@ -310,7 +344,8 @@ public final class ConfigRequest implements Parcelable { * awake. The configuration enables trading off latency vs. power (higher interval means * higher discovery latency but lower power). * - * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ}. + * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ} or + * {@link #NAN_BAND_6GHZ}. * @param interval A value of 1, 2, 3, 4, or 5 indicating an interval of 2^(interval-1). For * the 5GHz band a value of 0 indicates that the device will not be awake * for any discovery windows. @@ -319,13 +354,14 @@ public final class ConfigRequest implements Parcelable { * {@code builder.setDiscoveryWindowInterval(...).setMasterPreference(...)}. */ public Builder setDiscoveryWindowInterval(int band, int interval) { - if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ) { + if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ && band != NAN_BAND_6GHZ) { throw new IllegalArgumentException("Invalid band value"); } if ((band == NAN_BAND_24GHZ && (interval < 1 || interval > 5)) - || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5))) { + || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5)) + || (band == NAN_BAND_6GHZ && (interval < 0 || interval > 5))) { throw new IllegalArgumentException( - "Invalid interval value: 2.4 GHz [1,5] or 5GHz [0,5]"); + "Invalid interval value: 2.4 GHz [1,5] or 5GHz/6GHz [0,5]"); } mDiscoveryWindowInterval[band] = interval; @@ -342,8 +378,8 @@ public final class ConfigRequest implements Parcelable { "Invalid argument combination - must have Cluster Low <= Cluster High"); } - return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh, - mDiscoveryWindowInterval); + return new ConfigRequest(mSupport5gBand, mSupport6gBand, mMasterPreference, mClusterLow, + mClusterHigh, mDiscoveryWindowInterval); } } } diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java index 1886b7ef4c8d..a8844c1d3812 100644 --- a/wifi/java/android/net/wifi/aware/PublishConfig.java +++ b/wifi/java/android/net/wifi/aware/PublishConfig.java @@ -19,11 +19,10 @@ package android.net.wifi.aware; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.wifi.util.HexEncoding; import android.os.Parcel; import android.os.Parcelable; -import libcore.util.HexEncoding; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java index f0f758170bf2..76780f421af2 100644 --- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java +++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java @@ -19,11 +19,10 @@ package android.net.wifi.aware; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.wifi.util.HexEncoding; import android.os.Parcel; import android.os.Parcelable; -import libcore.util.HexEncoding; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java index 5ec4c8b13ee8..c66733472d0e 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java @@ -17,12 +17,11 @@ package android.net.wifi.aware; import android.net.NetworkSpecifier; +import android.net.wifi.util.HexEncoding; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; -import libcore.util.HexEncoding; - import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java index 7b37d652426d..81bf81e40199 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java @@ -19,6 +19,7 @@ package android.net.wifi.aware; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; @@ -26,6 +27,7 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkRequest; import android.net.NetworkSpecifier; +import android.net.wifi.util.HexEncoding; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -36,8 +38,6 @@ import android.os.Process; import android.os.RemoteException; import android.util.Log; -import libcore.util.HexEncoding; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; @@ -397,6 +397,17 @@ public class WifiAwareManager { } /** @hide */ + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + public void requestMacAddresses(int uid, List<Integer> peerIds, + IWifiAwareMacAddressProvider callback) { + try { + mService.requestMacAddresses(uid, peerIds, callback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId, @NonNull PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) { if (VDBG) { diff --git a/wifi/java/android/net/wifi/util/HexEncoding.java b/wifi/java/android/net/wifi/util/HexEncoding.java new file mode 100644 index 000000000000..9ebf947e2dc3 --- /dev/null +++ b/wifi/java/android/net/wifi/util/HexEncoding.java @@ -0,0 +1,183 @@ +/* + * 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 android.net.wifi.util; + +/** + * Hexadecimal encoding where each byte is represented by two hexadecimal digits. + * + * Note: this is copied from {@link libcore.util.HexEncoding}. + * + * @hide + */ +public class HexEncoding { + + private static final char[] LOWER_CASE_DIGITS = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + private static final char[] UPPER_CASE_DIGITS = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + + /** Hidden constructor to prevent instantiation. */ + private HexEncoding() {} + + /** + * Encodes the provided byte as a two-digit hexadecimal String value. + */ + public static String encodeToString(byte b, boolean upperCase) { + char[] digits = upperCase ? UPPER_CASE_DIGITS : LOWER_CASE_DIGITS; + char[] buf = new char[2]; // We always want two digits. + buf[0] = digits[(b >> 4) & 0xf]; + buf[1] = digits[b & 0xf]; + return new String(buf, 0, 2); + } + + /** + * Encodes the provided data as a sequence of hexadecimal characters. + */ + public static char[] encode(byte[] data) { + return encode(data, 0, data.length, true /* upperCase */); + } + + /** + * Encodes the provided data as a sequence of hexadecimal characters. + */ + public static char[] encode(byte[] data, boolean upperCase) { + return encode(data, 0, data.length, upperCase); + } + + /** + * Encodes the provided data as a sequence of hexadecimal characters. + */ + public static char[] encode(byte[] data, int offset, int len) { + return encode(data, offset, len, true /* upperCase */); + } + + /** + * Encodes the provided data as a sequence of hexadecimal characters. + */ + private static char[] encode(byte[] data, int offset, int len, boolean upperCase) { + char[] digits = upperCase ? UPPER_CASE_DIGITS : LOWER_CASE_DIGITS; + char[] result = new char[len * 2]; + for (int i = 0; i < len; i++) { + byte b = data[offset + i]; + int resultIndex = 2 * i; + result[resultIndex] = (digits[(b >> 4) & 0x0f]); + result[resultIndex + 1] = (digits[b & 0x0f]); + } + + return result; + } + + /** + * Encodes the provided data as a sequence of hexadecimal characters. + */ + public static String encodeToString(byte[] data) { + return encodeToString(data, true /* upperCase */); + } + + /** + * Encodes the provided data as a sequence of hexadecimal characters. + */ + public static String encodeToString(byte[] data, boolean upperCase) { + return new String(encode(data, upperCase)); + } + + /** + * Decodes the provided hexadecimal string into a byte array. Odd-length inputs + * are not allowed. + * + * Throws an {@code IllegalArgumentException} if the input is malformed. + */ + public static byte[] decode(String encoded) throws IllegalArgumentException { + return decode(encoded.toCharArray()); + } + + /** + * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar} + * is {@code true} odd-length inputs are allowed and the first character is interpreted + * as the lower bits of the first result byte. + * + * Throws an {@code IllegalArgumentException} if the input is malformed. + */ + public static byte[] decode(String encoded, boolean allowSingleChar) + throws IllegalArgumentException { + return decode(encoded.toCharArray(), allowSingleChar); + } + + /** + * Decodes the provided hexadecimal string into a byte array. Odd-length inputs + * are not allowed. + * + * Throws an {@code IllegalArgumentException} if the input is malformed. + */ + public static byte[] decode(char[] encoded) throws IllegalArgumentException { + return decode(encoded, false); + } + + /** + * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar} + * is {@code true} odd-length inputs are allowed and the first character is interpreted + * as the lower bits of the first result byte. + * + * Throws an {@code IllegalArgumentException} if the input is malformed. + */ + public static byte[] decode(char[] encoded, boolean allowSingleChar) + throws IllegalArgumentException { + int encodedLength = encoded.length; + int resultLengthBytes = (encodedLength + 1) / 2; + byte[] result = new byte[resultLengthBytes]; + + int resultOffset = 0; + int i = 0; + if (allowSingleChar) { + if ((encodedLength % 2) != 0) { + // Odd number of digits -- the first digit is the lower 4 bits of the first result + // byte. + result[resultOffset++] = (byte) toDigit(encoded, i); + i++; + } + } else { + if ((encodedLength % 2) != 0) { + throw new IllegalArgumentException("Invalid input length: " + encodedLength); + } + } + + for (; i < encodedLength; i += 2) { + result[resultOffset++] = (byte) ((toDigit(encoded, i) << 4) | toDigit(encoded, i + 1)); + } + + return result; + } + + private static int toDigit(char[] str, int offset) throws IllegalArgumentException { + // NOTE: that this isn't really a code point in the traditional sense, since we're + // just rejecting surrogate pairs outright. + int pseudoCodePoint = str[offset]; + + if ('0' <= pseudoCodePoint && pseudoCodePoint <= '9') { + return pseudoCodePoint - '0'; + } else if ('a' <= pseudoCodePoint && pseudoCodePoint <= 'f') { + return 10 + (pseudoCodePoint - 'a'); + } else if ('A' <= pseudoCodePoint && pseudoCodePoint <= 'F') { + return 10 + (pseudoCodePoint - 'A'); + } + + throw new IllegalArgumentException("Illegal char: " + str[offset] + " at offset " + offset); + } +} diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java index 367cfa069e74..524a53c03305 100644 --- a/wifi/java/com/android/server/wifi/BaseWifiService.java +++ b/wifi/java/com/android/server/wifi/BaseWifiService.java @@ -76,11 +76,14 @@ public class BaseWifiService extends IWifiManager.Stub { throw new UnsupportedOperationException(); } - @Override + /** @deprecated use {@link #getWifiActivityEnergyInfoAsync} instead */ + @Deprecated public WifiActivityEnergyInfo reportActivityInfo() { throw new UnsupportedOperationException(); } + /** @deprecated use {@link #getWifiActivityEnergyInfoAsync} instead */ + @Deprecated public void requestActivityInfo(ResultReceiver result) { throw new UnsupportedOperationException(); } @@ -544,19 +547,6 @@ public class BaseWifiService extends IWifiManager.Stub { throw new UnsupportedOperationException(); } - /** @deprecated replaced by {@link #registerScanResultsCallback(IScanResultsCallback)} */ - @Deprecated - public void registerScanResultsListener( - IBinder binder, IScanResultsListener listener, int listenerIdentifier) { - throw new UnsupportedOperationException(); - } - - /** @deprecated replaced by {@link #unregisterScanResultsCallback(IScanResultsCallback)} */ - @Deprecated - public void unregisterScanResultsListener(int listenerIdentifier) { - throw new UnsupportedOperationException(); - } - @Override public void registerScanResultsCallback(IScanResultsCallback callback) { throw new UnsupportedOperationException(); diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index de4514997b1c..f92d38c982b8 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -161,7 +161,7 @@ public class WifiManagerTest { mRunnable.run(); } }; - mWifiActivityEnergyInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0, 0); + mWifiActivityEnergyInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0); } /** @@ -1708,18 +1708,6 @@ public class WifiManagerTest { } /** - * Test behavior of {@link WifiManager#getControllerActivityEnergyInfo()} - */ - @Test - public void testGetControllerActivityEnergyInfo() throws Exception { - WifiActivityEnergyInfo activityEnergyInfo = - new WifiActivityEnergyInfo(5, 3, 3, 5, 5, 5, 5); - when(mWifiService.reportActivityInfo()).thenReturn(activityEnergyInfo); - - assertEquals(activityEnergyInfo, mWifiManager.getControllerActivityEnergyInfo()); - } - - /** * Tests that passing a null Executor to {@link WifiManager#getWifiActivityEnergyInfoAsync} * throws an exception. */ diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java index 8a5a0fd6805b..04aaa0bbcad0 100644 --- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java +++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java @@ -22,7 +22,6 @@ import android.net.MacAddress; import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.hotspot2.PasspointTestUtils; import android.os.Parcel; -import android.os.Process; import androidx.test.filters.SmallTest; @@ -35,8 +34,6 @@ import org.junit.Test; public class WifiNetworkSuggestionTest { private static final int TEST_UID = 45677; private static final int TEST_UID_OTHER = 45673; - private static final String TEST_PACKAGE_NAME = "com.test.packagename"; - private static final String TEST_PACKAGE_NAME_OTHER = "com.test.packagenameother"; private static final String TEST_SSID = "\"Test123\""; private static final String TEST_BSSID = "12:12:12:12:12:12"; private static final String TEST_SSID_1 = "\"Test1234\""; @@ -55,7 +52,6 @@ public class WifiNetworkSuggestionTest { .setIsAppInteractionRequired(true) .build(); - assertEquals(Process.myUid(), suggestion.suggestorUid); assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID); assertTrue(suggestion.wifiConfiguration.allowedKeyManagement .get(WifiConfiguration.KeyMgmt.NONE)); @@ -448,7 +444,7 @@ public class WifiNetworkSuggestionTest { configuration.BSSID = TEST_BSSID; configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion( - configuration, null, false, true, true, TEST_UID, TEST_PACKAGE_NAME); + configuration, null, false, true, true); Parcel parcelW = Parcel.obtain(); suggestion.writeToParcel(parcelW, 0); @@ -515,16 +511,14 @@ public class WifiNetworkSuggestionTest { configuration.BSSID = TEST_BSSID; configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); WifiNetworkSuggestion suggestion = - new WifiNetworkSuggestion(configuration, null, true, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration, null, true, false, true); WifiConfiguration configuration1 = new WifiConfiguration(); configuration1.SSID = TEST_SSID; configuration1.BSSID = TEST_BSSID; configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); WifiNetworkSuggestion suggestion1 = - new WifiNetworkSuggestion(configuration1, null, false, true, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration1, null, false, true, true); assertEquals(suggestion, suggestion1); assertEquals(suggestion.hashCode(), suggestion1.hashCode()); @@ -540,15 +534,13 @@ public class WifiNetworkSuggestionTest { configuration.SSID = TEST_SSID; configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSuggestion suggestion = - new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration, null, false, false, true); WifiConfiguration configuration1 = new WifiConfiguration(); configuration1.SSID = TEST_SSID_1; configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSuggestion suggestion1 = - new WifiNetworkSuggestion(configuration1, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration1, null, false, false, true); assertNotEquals(suggestion, suggestion1); } @@ -564,15 +556,13 @@ public class WifiNetworkSuggestionTest { configuration.BSSID = TEST_BSSID; configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSuggestion suggestion = - new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration, null, false, false, true); WifiConfiguration configuration1 = new WifiConfiguration(); configuration1.SSID = TEST_SSID; configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSuggestion suggestion1 = - new WifiNetworkSuggestion(configuration1, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration1, null, false, false, true); assertNotEquals(suggestion, suggestion1); } @@ -587,57 +577,18 @@ public class WifiNetworkSuggestionTest { configuration.SSID = TEST_SSID; configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSuggestion suggestion = - new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration, null, false, false, true); WifiConfiguration configuration1 = new WifiConfiguration(); configuration1.SSID = TEST_SSID; configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); WifiNetworkSuggestion suggestion1 = - new WifiNetworkSuggestion(configuration1, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration1, null, false, false, true); assertNotEquals(suggestion, suggestion1); } /** - * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same - * SSID, BSSID and key mgmt, but different UID. - */ - @Test - public void testWifiNetworkSuggestionEqualsFailsWhenUidIsDifferent() { - WifiConfiguration configuration = new WifiConfiguration(); - configuration.SSID = TEST_SSID; - configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - WifiNetworkSuggestion suggestion = - new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); - - WifiNetworkSuggestion suggestion1 = - new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID_OTHER, - TEST_PACKAGE_NAME); - - assertNotEquals(suggestion, suggestion1); - } - - /** - * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same - * SSID, BSSID and key mgmt, but different package name. - */ - @Test - public void testWifiNetworkSuggestionEqualsFailsWhenPackageNameIsDifferent() { - WifiConfiguration configuration = new WifiConfiguration(); - configuration.SSID = TEST_SSID; - configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion( - configuration, null, false, false, true, TEST_UID, TEST_PACKAGE_NAME); - - WifiNetworkSuggestion suggestion1 = new WifiNetworkSuggestion( - configuration, null, false, false, true, TEST_UID, TEST_PACKAGE_NAME_OTHER); - - assertNotEquals(suggestion, suggestion1); - } - /** * Check NetworkSuggestion equals returns {@code true} for 2 Passpoint network suggestions with * same FQDN. */ diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java index 3483ff8a4664..65fbf5b099d4 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java @@ -36,6 +36,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.MacAddress; import android.net.wifi.RttManager; +import android.net.wifi.util.HexEncoding; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -44,8 +45,6 @@ import android.os.test.TestLooper; import androidx.test.filters.SmallTest; -import libcore.util.HexEncoding; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -579,12 +578,15 @@ public class WifiAwareManagerTest { collector.checkThat("mMasterPreference", 0, equalTo(configRequest.mMasterPreference)); collector.checkThat("mSupport5gBand", true, equalTo(configRequest.mSupport5gBand)); - collector.checkThat("mDiscoveryWindowInterval.length", 2, + collector.checkThat("mSupport6gBand", false, equalTo(configRequest.mSupport6gBand)); + collector.checkThat("mDiscoveryWindowInterval.length", 3, equalTo(configRequest.mDiscoveryWindowInterval.length)); collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT, equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ])); collector.checkThat("mDiscoveryWindowInterval[5Hz]", ConfigRequest.DW_INTERVAL_NOT_INIT, equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ])); + collector.checkThat("mDiscoveryWindowInterval[6Hz]", ConfigRequest.DW_INTERVAL_NOT_INIT, + equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_6GHZ])); } @Test @@ -593,12 +595,16 @@ public class WifiAwareManagerTest { final int clusterLow = 5; final int masterPreference = 55; final boolean supportBand5g = true; + final boolean supportBand6g = true; final int dwWindow5GHz = 3; + final int dwWindow6GHz = 4; ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh) .setClusterLow(clusterLow).setMasterPreference(masterPreference) .setSupport5gBand(supportBand5g) + .setSupport6gBand(supportBand6g) .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz) + .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_6GHZ, dwWindow6GHz) .build(); collector.checkThat("mClusterHigh", clusterHigh, equalTo(configRequest.mClusterHigh)); @@ -606,12 +612,15 @@ public class WifiAwareManagerTest { collector.checkThat("mMasterPreference", masterPreference, equalTo(configRequest.mMasterPreference)); collector.checkThat("mSupport5gBand", supportBand5g, equalTo(configRequest.mSupport5gBand)); - collector.checkThat("mDiscoveryWindowInterval.length", 2, + collector.checkThat("mSupport6gBand", supportBand6g, equalTo(configRequest.mSupport6gBand)); + collector.checkThat("mDiscoveryWindowInterval.length", 3, equalTo(configRequest.mDiscoveryWindowInterval.length)); collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT, equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ])); collector.checkThat("mDiscoveryWindowInterval[5GHz]", dwWindow5GHz, equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ])); + collector.checkThat("mDiscoveryWindowInterval[6GHz]", dwWindow6GHz, + equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_6GHZ])); } @Test(expected = IllegalArgumentException.class) @@ -690,14 +699,18 @@ public class WifiAwareManagerTest { final int clusterLow = 25; final int masterPreference = 177; final boolean supportBand5g = true; + final boolean supportBand6g = false; final int dwWindow24GHz = 1; final int dwWindow5GHz = 5; + final int dwWindow6GHz = 4; ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh) .setClusterLow(clusterLow).setMasterPreference(masterPreference) .setSupport5gBand(supportBand5g) + .setSupport6gBand(supportBand6g) .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwWindow24GHz) .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz) + .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_6GHZ, dwWindow6GHz) .build(); Parcel parcelW = Parcel.obtain(); diff --git a/wifi/tests/src/android/net/wifi/util/HexEncodingTest.java b/wifi/tests/src/android/net/wifi/util/HexEncodingTest.java new file mode 100644 index 000000000000..0d751389e244 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/util/HexEncodingTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.util; + +import static android.net.wifi.util.HexEncoding.decode; +import static android.net.wifi.util.HexEncoding.encode; +import static android.net.wifi.util.HexEncoding.encodeToString; + +import junit.framework.TestCase; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Locale; + +/** Copied from {@link libcore.libcore.util.HexEncodingTest}. */ +public class HexEncodingTest extends TestCase { + + public void testEncodeByte() { + Object[][] testCases = new Object[][]{ + {0x01, "01"}, + {0x09, "09"}, + {0x0A, "0A"}, + {0x0F, "0F"}, + {0x10, "10"}, + {0x1F, "1F"}, + {0x20, "20"}, + {0x7F, "7F"}, + {0x80, "80"}, + {0xFF, "FF"}, + }; + for (Object[] testCase : testCases) { + Number toEncode = (Number) testCase[0]; + String expected = (String) testCase[1]; + + String actualUpper = encodeToString(toEncode.byteValue(), true /* upperCase */); + assertEquals(upper(expected), actualUpper); + + String actualLower = encodeToString(toEncode.byteValue(), false /* upperCase */); + assertEquals(lower(expected), actualLower); + } + } + + public void testEncodeBytes() { + Object[][] testCases = new Object[][]{ + {"avocados".getBytes(StandardCharsets.UTF_8), "61766F6361646F73"}, + }; + + for (Object[] testCase : testCases) { + byte[] bytes = (byte[]) testCase[0]; + String encodedLower = lower((String) testCase[1]); + String encodedUpper = upper((String) testCase[1]); + + assertArraysEqual(encodedUpper.toCharArray(), encode(bytes)); + assertArraysEqual(encodedUpper.toCharArray(), encode(bytes, true /* upperCase */)); + assertArraysEqual(encodedLower.toCharArray(), encode(bytes, false /* upperCase */)); + + assertArraysEqual(bytes, decode(encode(bytes), false /* allowSingleChar */)); + + // Make sure we can handle lower case hex encodings as well. + assertArraysEqual(bytes, + decode(encodedLower.toCharArray(), false /* allowSingleChar */)); + } + } + + public void testDecode_allow4Bit() { + assertArraysEqual(new byte[]{6}, decode("6".toCharArray(), true)); + assertArraysEqual(new byte[]{6, 0x76}, decode("676".toCharArray(), true)); + } + + public void testDecode_disallow4Bit() { + try { + decode("676".toCharArray(), false /* allowSingleChar */); + fail(); + } catch (IllegalArgumentException expected) { + } + } + + public void testDecode_invalid() { + try { + decode("DEADBARD".toCharArray(), false /* allowSingleChar */); + fail(); + } catch (IllegalArgumentException expected) { + } + + // This demonstrates a difference in behaviour from apache commons : apache + // commons uses Character.isDigit and would successfully decode a string with + // arabic and devanagari characters. + try { + decode("६१٧٥٥F6361646F73".toCharArray(), false /* allowSingleChar */); + fail(); + } catch (IllegalArgumentException expected) { + } + + try { + decode("#%6361646F73".toCharArray(), false /* allowSingleChar */); + fail(); + } catch (IllegalArgumentException expected) { + } + } + + private static void assertArraysEqual(char[] lhs, char[] rhs) { + assertEquals(new String(lhs), new String(rhs)); + } + + private static void assertArraysEqual(byte[] lhs, byte[] rhs) { + assertEquals(Arrays.toString(lhs), Arrays.toString(rhs)); + } + + private static String lower(String string) { + return string.toLowerCase(Locale.ROOT); + } + + private static String upper(String string) { + return string.toUpperCase(Locale.ROOT); + } +} |